@morphllm/morphsdk 0.2.183 → 0.2.184
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-4CAD3PJZ.js → chunk-2UOKVPIL.js} +2 -2
- package/dist/{chunk-SNEZIVPK.js → chunk-37BHEELU.js} +2 -2
- package/dist/{chunk-7POEHIJD.js → chunk-54OLRNWB.js} +2 -2
- package/dist/{chunk-YQCT5FNK.js → chunk-7ZZH5ZHL.js} +3 -26
- package/dist/chunk-7ZZH5ZHL.js.map +1 -0
- package/dist/{chunk-4AL5UU43.js → chunk-A77UFLGX.js} +3 -3
- package/dist/{chunk-Q5YPHAVJ.js → chunk-C3B5MCJI.js} +4 -4
- package/dist/{chunk-Z34FIIIY.js → chunk-CEA3R4J7.js} +3 -3
- package/dist/{chunk-FTEHMPEN.js → chunk-CRX7U4N6.js} +4 -4
- package/dist/{chunk-57TTNFVC.js → chunk-DAX3ANOA.js} +3 -3
- package/dist/{chunk-2ZJ7HYSD.js → chunk-DNVCIIMV.js} +4 -4
- package/dist/{chunk-FJCXN2MZ.js → chunk-EO64JD3Y.js} +4 -4
- package/dist/{chunk-VLE7NFGC.js → chunk-FGHJS67Z.js} +2 -2
- package/dist/{chunk-ZP25QXTM.js → chunk-FZYE6TIU.js} +26 -26
- package/dist/{chunk-H4Z53LJO.js → chunk-GG3567UT.js} +2 -2
- package/dist/{chunk-D2KFCCAO.js → chunk-JZJ75Z47.js} +3 -3
- package/dist/{chunk-D2KFCCAO.js.map → chunk-JZJ75Z47.js.map} +1 -1
- package/dist/{chunk-ALIS2RQM.js → chunk-LG4ZDMXH.js} +2 -2
- package/dist/{chunk-4FZMH2PJ.js → chunk-MN7K4UPX.js} +2 -2
- package/dist/{chunk-BIENM7HG.js → chunk-NNC7NUNL.js} +2 -2
- package/dist/{chunk-Q4FFGCHN.js → chunk-NZHRYBXS.js} +2 -2
- package/dist/{chunk-LN7GNFET.js → chunk-OPNTDMHH.js} +4 -4
- package/dist/{chunk-7PTLVOSX.js → chunk-PHXOP6I6.js} +2 -2
- package/dist/{chunk-YJMW3BWV.js → chunk-PJDTQSBL.js} +4 -4
- package/dist/{chunk-5Y46GS6X.js → chunk-QXU2RXTD.js} +4 -4
- package/dist/{chunk-RVQWKMNC.js → chunk-R3MDQ6II.js} +2 -2
- package/dist/{chunk-HC3E2X3Q.js → chunk-RPX46ER3.js} +4 -4
- package/dist/{chunk-L6XLP5KW.js → chunk-RSAWA67J.js} +4 -4
- package/dist/{chunk-6RGCQJCA.js → chunk-RYITZGY6.js} +2 -2
- package/dist/{chunk-3CKKTPPO.js → chunk-TYMBLS7J.js} +2 -2
- package/dist/{chunk-STJTJDAV.js → chunk-UEBROM7G.js} +1 -11
- package/dist/chunk-UEBROM7G.js.map +1 -0
- package/dist/{chunk-5B37BXPY.js → chunk-VGNNHWAE.js} +2 -2
- package/dist/{chunk-MZSQVPMW.js → chunk-VXEP6Q2E.js} +4 -4
- package/dist/{chunk-F2AEMPYM.js → chunk-WKK57U64.js} +2 -2
- package/dist/{chunk-XZSCODV4.js → chunk-YYZX5TMX.js} +2 -2
- package/dist/client.cjs +2 -25
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +29 -29
- package/dist/core/client.cjs +2 -2
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.js +4 -4
- package/dist/core/error.cjs +2 -2
- package/dist/core/error.cjs.map +1 -1
- package/dist/core/error.js +3 -3
- package/dist/core/index.cjs +2 -2
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +4 -4
- package/dist/edge.cjs +2 -2
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +7 -7
- package/dist/git/client.cjs +2 -2
- package/dist/git/client.cjs.map +1 -1
- package/dist/git/client.js +5 -5
- package/dist/git/index.cjs +2 -2
- package/dist/git/index.cjs.map +1 -1
- package/dist/git/index.js +5 -5
- package/dist/index.cjs +2 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -34
- package/dist/modelrouter/core.cjs +2 -2
- package/dist/modelrouter/core.cjs.map +1 -1
- package/dist/modelrouter/core.js +5 -5
- package/dist/modelrouter/index.cjs +2 -2
- package/dist/modelrouter/index.cjs.map +1 -1
- package/dist/modelrouter/index.js +5 -5
- package/dist/subagents/anthropic.cjs +2 -2
- package/dist/subagents/anthropic.cjs.map +1 -1
- package/dist/subagents/anthropic.js +9 -9
- package/dist/subagents/vercel.cjs +2 -2
- package/dist/subagents/vercel.cjs.map +1 -1
- package/dist/subagents/vercel.js +9 -9
- package/dist/tools/browser/anthropic.cjs +2 -2
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +7 -7
- package/dist/tools/browser/core.cjs +2 -2
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.js +6 -6
- package/dist/tools/browser/index.cjs +2 -2
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.js +11 -11
- package/dist/tools/browser/openai.cjs +2 -2
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +7 -7
- package/dist/tools/browser/profiles/core.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.js +7 -7
- package/dist/tools/codebase_search/anthropic.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/codebase_search/index.cjs.map +1 -1
- package/dist/tools/codebase_search/index.js +10 -10
- package/dist/tools/codebase_search/openai.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/compact/core.cjs.map +1 -1
- package/dist/tools/compact/core.js +5 -5
- package/dist/tools/compact/index.cjs +2 -2
- package/dist/tools/compact/index.cjs.map +1 -1
- package/dist/tools/compact/index.js +6 -6
- package/dist/tools/fastapply/anthropic.cjs +2 -2
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +7 -7
- package/dist/tools/fastapply/apply.cjs +2 -2
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.js +2 -2
- package/dist/tools/fastapply/core.cjs +2 -2
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +6 -6
- package/dist/tools/fastapply/index.cjs +2 -2
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +11 -11
- package/dist/tools/fastapply/openai.cjs +2 -2
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +7 -7
- package/dist/tools/fastapply/vercel.cjs +2 -2
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +7 -7
- package/dist/tools/index.cjs +2 -2
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +11 -11
- package/dist/tools/reflex/core.cjs +2 -25
- package/dist/tools/reflex/core.cjs.map +1 -1
- package/dist/tools/reflex/core.d.ts +1 -6
- package/dist/tools/reflex/core.js +5 -5
- package/dist/tools/reflex/index.cjs +2 -25
- package/dist/tools/reflex/index.cjs.map +1 -1
- package/dist/tools/reflex/index.js +5 -5
- package/dist/tools/reflex/types.cjs.map +1 -1
- package/dist/tools/reflex/types.d.ts +2 -30
- package/dist/tools/utils/resilience.cjs +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +8 -8
- package/dist/tools/warp_grep/harness.js +2 -2
- package/dist/tools/warp_grep/index.cjs +2 -2
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.js +10 -10
- package/dist/tools/warp_grep/openai.cjs +2 -2
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +9 -9
- package/dist/tools/warp_grep/providers/local.js +2 -2
- package/dist/tools/warp_grep/vercel.cjs +2 -2
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +9 -9
- package/dist/tracing/core.cjs +0 -38
- package/dist/tracing/core.cjs.map +1 -1
- package/dist/tracing/core.d.ts +2 -6
- package/dist/tracing/core.js +1 -2
- package/dist/tracing/index.cjs +0 -38
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.ts +1 -1
- package/dist/tracing/index.js +1 -2
- package/dist/tracing/types.cjs.map +1 -1
- package/dist/tracing/types.d.ts +1 -14
- package/dist/version.cjs +2 -2
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-PICGNBUE.js +0 -35
- package/dist/chunk-PICGNBUE.js.map +0 -1
- package/dist/chunk-STJTJDAV.js.map +0 -1
- package/dist/chunk-YQCT5FNK.js.map +0 -1
- package/dist/tracing/signals.cjs +0 -59
- package/dist/tracing/signals.cjs.map +0 -1
- package/dist/tracing/signals.d.ts +0 -13
- package/dist/tracing/signals.js +0 -8
- package/dist/tracing/signals.js.map +0 -1
- /package/dist/{chunk-4CAD3PJZ.js.map → chunk-2UOKVPIL.js.map} +0 -0
- /package/dist/{chunk-SNEZIVPK.js.map → chunk-37BHEELU.js.map} +0 -0
- /package/dist/{chunk-7POEHIJD.js.map → chunk-54OLRNWB.js.map} +0 -0
- /package/dist/{chunk-4AL5UU43.js.map → chunk-A77UFLGX.js.map} +0 -0
- /package/dist/{chunk-Q5YPHAVJ.js.map → chunk-C3B5MCJI.js.map} +0 -0
- /package/dist/{chunk-Z34FIIIY.js.map → chunk-CEA3R4J7.js.map} +0 -0
- /package/dist/{chunk-FTEHMPEN.js.map → chunk-CRX7U4N6.js.map} +0 -0
- /package/dist/{chunk-57TTNFVC.js.map → chunk-DAX3ANOA.js.map} +0 -0
- /package/dist/{chunk-2ZJ7HYSD.js.map → chunk-DNVCIIMV.js.map} +0 -0
- /package/dist/{chunk-FJCXN2MZ.js.map → chunk-EO64JD3Y.js.map} +0 -0
- /package/dist/{chunk-VLE7NFGC.js.map → chunk-FGHJS67Z.js.map} +0 -0
- /package/dist/{chunk-ZP25QXTM.js.map → chunk-FZYE6TIU.js.map} +0 -0
- /package/dist/{chunk-H4Z53LJO.js.map → chunk-GG3567UT.js.map} +0 -0
- /package/dist/{chunk-ALIS2RQM.js.map → chunk-LG4ZDMXH.js.map} +0 -0
- /package/dist/{chunk-4FZMH2PJ.js.map → chunk-MN7K4UPX.js.map} +0 -0
- /package/dist/{chunk-BIENM7HG.js.map → chunk-NNC7NUNL.js.map} +0 -0
- /package/dist/{chunk-Q4FFGCHN.js.map → chunk-NZHRYBXS.js.map} +0 -0
- /package/dist/{chunk-LN7GNFET.js.map → chunk-OPNTDMHH.js.map} +0 -0
- /package/dist/{chunk-7PTLVOSX.js.map → chunk-PHXOP6I6.js.map} +0 -0
- /package/dist/{chunk-YJMW3BWV.js.map → chunk-PJDTQSBL.js.map} +0 -0
- /package/dist/{chunk-5Y46GS6X.js.map → chunk-QXU2RXTD.js.map} +0 -0
- /package/dist/{chunk-RVQWKMNC.js.map → chunk-R3MDQ6II.js.map} +0 -0
- /package/dist/{chunk-HC3E2X3Q.js.map → chunk-RPX46ER3.js.map} +0 -0
- /package/dist/{chunk-L6XLP5KW.js.map → chunk-RSAWA67J.js.map} +0 -0
- /package/dist/{chunk-6RGCQJCA.js.map → chunk-RYITZGY6.js.map} +0 -0
- /package/dist/{chunk-3CKKTPPO.js.map → chunk-TYMBLS7J.js.map} +0 -0
- /package/dist/{chunk-5B37BXPY.js.map → chunk-VGNNHWAE.js.map} +0 -0
- /package/dist/{chunk-MZSQVPMW.js.map → chunk-VXEP6Q2E.js.map} +0 -0
- /package/dist/{chunk-F2AEMPYM.js.map → chunk-WKK57U64.js.map} +0 -0
- /package/dist/{chunk-XZSCODV4.js.map → chunk-YYZX5TMX.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-FGHJS67Z.js";
|
|
9
9
|
import "../../chunk-Q6QCHAMD.js";
|
|
10
10
|
import {
|
|
11
11
|
formatResult
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-RPX46ER3.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-NZHRYBXS.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-NNC7NUNL.js";
|
|
21
|
+
import "../../chunk-A77UFLGX.js";
|
|
22
|
+
import "../../chunk-QXU2RXTD.js";
|
|
23
23
|
import "../../chunk-F3NCFNUX.js";
|
|
24
|
-
import "../../chunk-
|
|
25
|
-
import "../../chunk-
|
|
26
|
-
import "../../chunk-
|
|
24
|
+
import "../../chunk-RYITZGY6.js";
|
|
25
|
+
import "../../chunk-YYZX5TMX.js";
|
|
26
|
+
import "../../chunk-JZJ75Z47.js";
|
|
27
27
|
import "../../chunk-LKFZBBTD.js";
|
|
28
28
|
import "../../chunk-PZ5AY32C.js";
|
|
29
29
|
export {
|
package/dist/tracing/core.cjs
CHANGED
|
@@ -270,37 +270,6 @@ function createNoopInteraction(initial) {
|
|
|
270
270
|
};
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
// tracing/signals.ts
|
|
274
|
-
async function shipSignal(endpoint, apiKey, signals, debug = false, timeoutMs = 1e4) {
|
|
275
|
-
if (signals.length === 0) return;
|
|
276
|
-
const controller = new AbortController();
|
|
277
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
278
|
-
try {
|
|
279
|
-
const res = await fetch(endpoint, {
|
|
280
|
-
method: "POST",
|
|
281
|
-
headers: {
|
|
282
|
-
"Content-Type": "application/json",
|
|
283
|
-
Authorization: `Bearer ${apiKey}`
|
|
284
|
-
},
|
|
285
|
-
body: JSON.stringify({ signals }),
|
|
286
|
-
signal: controller.signal
|
|
287
|
-
});
|
|
288
|
-
if (!res.ok) {
|
|
289
|
-
const body = await res.text().catch(() => "");
|
|
290
|
-
console.warn(`[morph-tracing] signal POST failed (${res.status}): ${body}`);
|
|
291
|
-
} else if (debug) {
|
|
292
|
-
console.log(`[morph-tracing] shipped ${signals.length} signal(s)`);
|
|
293
|
-
}
|
|
294
|
-
} catch (err) {
|
|
295
|
-
console.warn(
|
|
296
|
-
"[morph-tracing] signal POST error:",
|
|
297
|
-
err instanceof Error ? err.message : err
|
|
298
|
-
);
|
|
299
|
-
} finally {
|
|
300
|
-
clearTimeout(timer);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
273
|
// tracing/core.ts
|
|
305
274
|
var DEFAULT_BASE_URL = "https://api.morphllm.com";
|
|
306
275
|
function log(debug, ...args) {
|
|
@@ -319,7 +288,6 @@ var MorphTracing = class {
|
|
|
319
288
|
this.cfg = {
|
|
320
289
|
apiKey,
|
|
321
290
|
baseUrl,
|
|
322
|
-
signalsEndpoint: `${baseUrl}/v1/signals`,
|
|
323
291
|
appName: config.appName ?? process.env.npm_package_name ?? "morph-app",
|
|
324
292
|
disableBatching: config.disableBatching ?? !isProd,
|
|
325
293
|
traceContent: config.traceContent ?? true,
|
|
@@ -404,12 +372,6 @@ var MorphTracing = class {
|
|
|
404
372
|
metadata(opts) {
|
|
405
373
|
return metadata(opts);
|
|
406
374
|
}
|
|
407
|
-
/** Attach a feedback/quality signal to an interaction by eventId. */
|
|
408
|
-
async trackSignal(signal) {
|
|
409
|
-
if (!this.enabled) return;
|
|
410
|
-
const signals = Array.isArray(signal) ? signal : [signal];
|
|
411
|
-
await shipSignal(this.cfg.signalsEndpoint, this.cfg.apiKey, signals, this.cfg.debug);
|
|
412
|
-
}
|
|
413
375
|
/** Span processor for `useExternalOtel: true` integrations. */
|
|
414
376
|
createSpanProcessor(options) {
|
|
415
377
|
const exporter = options?.exporter ?? new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
@@ -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 {\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"]}
|
|
1
|
+
{"version":3,"sources":["../../tracing/core.ts","../../tracing/interaction.ts","../../tracing/otel.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 and tools.\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 type {\n MetadataOptions,\n MorphTracingConfig,\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 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()`, and 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 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 /** 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"],"mappings":"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","names":["traceloop","uuid"]}
|
package/dist/tracing/core.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as traceloop from '@traceloop/node-server-sdk';
|
|
2
2
|
import { Interaction, Tracer } from './interaction.js';
|
|
3
|
-
import { MorphTracingConfig, TraceContext, MetadataOptions
|
|
3
|
+
import { MorphTracingConfig, TraceContext, MetadataOptions } from './types.js';
|
|
4
4
|
|
|
5
5
|
interface ResolvedConfig {
|
|
6
6
|
apiKey: string;
|
|
7
7
|
baseUrl: string;
|
|
8
|
-
signalsEndpoint: string;
|
|
9
8
|
appName: string;
|
|
10
9
|
disableBatching: boolean;
|
|
11
10
|
traceContent: boolean;
|
|
@@ -14,8 +13,7 @@ interface ResolvedConfig {
|
|
|
14
13
|
}
|
|
15
14
|
/**
|
|
16
15
|
* Handle returned by {@link morphTracing}. Create interactions with `begin()`,
|
|
17
|
-
* get a non-interactive `tracer()`,
|
|
18
|
-
* flush/shutdown the exporter.
|
|
16
|
+
* get a non-interactive `tracer()`, and flush/shutdown the exporter.
|
|
19
17
|
*/
|
|
20
18
|
declare class MorphTracing {
|
|
21
19
|
private readonly cfg;
|
|
@@ -40,8 +38,6 @@ declare class MorphTracing {
|
|
|
40
38
|
tracer(globalProperties?: Record<string, string>): Tracer;
|
|
41
39
|
/** Build Vercel AI SDK telemetry metadata (see `@morphllm/morphsdk/tracing/otel`). */
|
|
42
40
|
metadata(opts: MetadataOptions): Record<string, string>;
|
|
43
|
-
/** Attach a feedback/quality signal to an interaction by eventId. */
|
|
44
|
-
trackSignal(signal: SignalEvent | SignalEvent[]): Promise<void>;
|
|
45
41
|
/** Span processor for `useExternalOtel: true` integrations. */
|
|
46
42
|
createSpanProcessor(options?: Parameters<typeof traceloop.createSpanProcessor>[0]): ReturnType<typeof traceloop.createSpanProcessor>;
|
|
47
43
|
/** Flush any batched spans immediately. Safe to call when idle. */
|
package/dist/tracing/core.js
CHANGED
package/dist/tracing/index.cjs
CHANGED
|
@@ -280,37 +280,6 @@ function createNoopInteraction(initial) {
|
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
// tracing/signals.ts
|
|
284
|
-
async function shipSignal(endpoint, apiKey, signals, debug = false, timeoutMs = 1e4) {
|
|
285
|
-
if (signals.length === 0) return;
|
|
286
|
-
const controller = new AbortController();
|
|
287
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
288
|
-
try {
|
|
289
|
-
const res = await fetch(endpoint, {
|
|
290
|
-
method: "POST",
|
|
291
|
-
headers: {
|
|
292
|
-
"Content-Type": "application/json",
|
|
293
|
-
Authorization: `Bearer ${apiKey}`
|
|
294
|
-
},
|
|
295
|
-
body: JSON.stringify({ signals }),
|
|
296
|
-
signal: controller.signal
|
|
297
|
-
});
|
|
298
|
-
if (!res.ok) {
|
|
299
|
-
const body = await res.text().catch(() => "");
|
|
300
|
-
console.warn(`[morph-tracing] signal POST failed (${res.status}): ${body}`);
|
|
301
|
-
} else if (debug) {
|
|
302
|
-
console.log(`[morph-tracing] shipped ${signals.length} signal(s)`);
|
|
303
|
-
}
|
|
304
|
-
} catch (err) {
|
|
305
|
-
console.warn(
|
|
306
|
-
"[morph-tracing] signal POST error:",
|
|
307
|
-
err instanceof Error ? err.message : err
|
|
308
|
-
);
|
|
309
|
-
} finally {
|
|
310
|
-
clearTimeout(timer);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
283
|
// tracing/core.ts
|
|
315
284
|
var DEFAULT_BASE_URL = "https://api.morphllm.com";
|
|
316
285
|
function log(debug, ...args) {
|
|
@@ -329,7 +298,6 @@ var MorphTracing = class {
|
|
|
329
298
|
this.cfg = {
|
|
330
299
|
apiKey,
|
|
331
300
|
baseUrl,
|
|
332
|
-
signalsEndpoint: `${baseUrl}/v1/signals`,
|
|
333
301
|
appName: config.appName ?? process.env.npm_package_name ?? "morph-app",
|
|
334
302
|
disableBatching: config.disableBatching ?? !isProd,
|
|
335
303
|
traceContent: config.traceContent ?? true,
|
|
@@ -414,12 +382,6 @@ var MorphTracing = class {
|
|
|
414
382
|
metadata(opts) {
|
|
415
383
|
return metadata(opts);
|
|
416
384
|
}
|
|
417
|
-
/** Attach a feedback/quality signal to an interaction by eventId. */
|
|
418
|
-
async trackSignal(signal) {
|
|
419
|
-
if (!this.enabled) return;
|
|
420
|
-
const signals = Array.isArray(signal) ? signal : [signal];
|
|
421
|
-
await shipSignal(this.cfg.signalsEndpoint, this.cfg.apiKey, signals, this.cfg.debug);
|
|
422
|
-
}
|
|
423
385
|
/** Span processor for `useExternalOtel: true` integrations. */
|
|
424
386
|
createSpanProcessor(options) {
|
|
425
387
|
const exporter = options?.exporter ?? new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../tracing/index.ts","../../tracing/core.ts","../../tracing/interaction.ts","../../tracing/otel.ts","../../tracing/signals.ts"],"sourcesContent":["/**\n * Morph Tracing — instrument the top AI SDKs and ship traces to Morph.\n *\n * @example\n * ```ts\n * import { morphTracing } from \"@morphllm/morphsdk/tracing\";\n *\n * const morph = morphTracing({ apiKey: process.env.MORPH_API_KEY });\n * // OpenAI / Anthropic / Vercel AI SDK calls are now traced automatically.\n *\n * const it = morph.begin({ userId: \"u1\", convoId: \"c1\", event: \"chat\" });\n * it.setInput(\"what's the weather?\");\n * const answer = await it.withTool({ name: \"get_weather\" }, () => getWeather());\n * await it.finish({ output: answer });\n *\n * // Feedback later:\n * await morph.trackSignal({ eventId: it.getEventId()!, verdict: \"good\" });\n * ```\n *\n * For the Vercel AI SDK, also see `@morphllm/morphsdk/tracing/otel`'s `metadata()` helper.\n */\nexport { morphTracing, MorphTracing } from './core.js';\nexport type { Interaction, Tracer } from './interaction.js';\nexport { metadata } from './otel.js';\nexport type {\n MorphTracingConfig,\n InstrumentModules,\n TraceContext,\n SpanParams,\n ToolParams,\n ToolSpan,\n TrackToolParams,\n FinishOptions,\n SignalEvent,\n MetadataOptions,\n} from './types.js';\n\nexport * as otel from './otel.js';\n","/**\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"]}
|
|
1
|
+
{"version":3,"sources":["../../tracing/index.ts","../../tracing/core.ts","../../tracing/interaction.ts","../../tracing/otel.ts"],"sourcesContent":["/**\n * Morph Tracing — instrument the top AI SDKs and ship traces to Morph.\n *\n * @example\n * ```ts\n * import { morphTracing } from \"@morphllm/morphsdk/tracing\";\n *\n * const morph = morphTracing({ apiKey: process.env.MORPH_API_KEY });\n * // OpenAI / Anthropic / Vercel AI SDK calls are now traced automatically.\n *\n * const it = morph.begin({ userId: \"u1\", convoId: \"c1\", event: \"chat\" });\n * it.setInput(\"what's the weather?\");\n * const answer = await it.withTool({ name: \"get_weather\" }, () => getWeather());\n * await it.finish({ output: answer });\n * ```\n *\n * For the Vercel AI SDK, also see `@morphllm/morphsdk/tracing/otel`'s `metadata()` helper.\n */\nexport { morphTracing, MorphTracing } from './core.js';\nexport type { Interaction, Tracer } from './interaction.js';\nexport { metadata } from './otel.js';\nexport type {\n MorphTracingConfig,\n InstrumentModules,\n TraceContext,\n SpanParams,\n ToolParams,\n ToolSpan,\n TrackToolParams,\n FinishOptions,\n MetadataOptions,\n} from './types.js';\n\nexport * as otel from './otel.js';\n","/**\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 and tools.\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 type {\n MetadataOptions,\n MorphTracingConfig,\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 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()`, and 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 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 /** 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"],"mappings":"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","names":["traceloop","uuid"]}
|
package/dist/tracing/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MorphTracing, morphTracing } from './core.js';
|
|
2
2
|
export { Interaction, Tracer } from './interaction.js';
|
|
3
3
|
export { m as metadata, o as otel } from '../otel-CG0uqXjp.js';
|
|
4
|
-
export { FinishOptions, InstrumentModules, MetadataOptions, MorphTracingConfig,
|
|
4
|
+
export { FinishOptions, InstrumentModules, MetadataOptions, MorphTracingConfig, SpanParams, ToolParams, ToolSpan, TraceContext, TrackToolParams } from './types.js';
|
|
5
5
|
import '@traceloop/node-server-sdk';
|
package/dist/tracing/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../tracing/types.ts"],"sourcesContent":["/**\n * Morph Tracing — public types.\n *\n * Morph Tracing instruments the top AI SDKs (OpenAI, Anthropic, Vercel AI SDK,\n * Bedrock, Vertex, Cohere, Together, LangChain, LlamaIndex, …) and ships\n * OpenTelemetry spans to Morph. It is a thin, Morph-branded layer over\n * OpenLLMetry / Traceloop, exactly like `raindrop-ai` is.\n */\n\n/**\n * Modules to explicitly instrument. Pass the imported SDK module/constructor so\n * Traceloop patches the exact instance your app uses. If omitted, all supported\n * libraries are auto-instrumented.\n */\nexport interface InstrumentModules {\n openAI?: unknown;\n anthropic?: unknown;\n cohere?: unknown;\n bedrock?: unknown;\n google_vertexai?: unknown;\n google_aiplatform?: unknown;\n pinecone?: unknown;\n together?: unknown;\n langchain?: boolean;\n llamaIndex?: unknown;\n chromadb?: unknown;\n qdrant?: unknown;\n mcp?: unknown;\n [key: string]: unknown;\n}\n\nexport interface MorphTracingConfig {\n /**\n * Morph API key. Defaults to `process.env.MORPH_API_KEY`. Sent as\n * `Authorization: Bearer <apiKey>` to the trace ingest endpoint.\n */\n apiKey?: string;\n /**\n * Base URL for the Morph ingest API. Traces are POSTed to `${baseUrl}/v1/traces`.\n * Defaults to `process.env.MORPH_TRACES_URL` then `https://api.morphllm.com`.\n */\n baseUrl?: string;\n /** Service/app name attached to every span. Defaults to the host package name. */\n appName?: string;\n /**\n * When true, the SDK initializes nothing and ships nothing. Useful for tests\n * and local/dev. Defaults to false.\n */\n disabled?: boolean;\n /**\n * Send spans immediately instead of batching. Defaults to true outside\n * production (`NODE_ENV !== 'production'`) so local runs flush instantly.\n */\n disableBatching?: boolean;\n /**\n * Capture prompt/response content on spans. Set false for zero-data-retention.\n * Defaults to true.\n */\n traceContent?: boolean;\n /** Explicit modules to instrument. Omit to auto-instrument everything. */\n instrumentModules?: InstrumentModules;\n /**\n * Set true when you run your own OpenTelemetry NodeSDK. Morph will not start\n * its own SDK; instead use `getInstrumentations()` and `createSpanProcessor()`.\n */\n useExternalOtel?: boolean;\n /** Extra headers merged onto the OTLP exporter request. */\n headers?: Record<string, string>;\n /** Verbose `[morph-tracing]` logging. Defaults to `MORPH_TRACING_DEBUG=1`. */\n debug?: boolean;\n}\n\n/** Identity + content for a single traced AI interaction. */\nexport interface TraceContext {\n /** Stable identifier for the interaction; auto-generated if omitted. */\n eventId?: string;\n /** End-user identifier. */\n userId?: string;\n /** Conversation/session identifier grouping related interactions. */\n convoId?: string;\n /** Event name (defaults to \"ai_generation\" on the backend). */\n event?: string;\n /** User input for this interaction. */\n input?: string;\n /** Arbitrary string metadata propagated onto spans. */\n properties?: Record<string, string>;\n}\n\nexport interface SpanParams {\n name: string;\n properties?: Record<string, string>;\n}\n\nexport interface ToolParams {\n name: string;\n version?: number;\n properties?: Record<string, string>;\n}\n\n/** Record a tool invocation that has already completed. */\nexport interface TrackToolParams {\n name: string;\n input?: unknown;\n output?: unknown;\n durationMs?: number;\n error?: Error | string;\n properties?: Record<string, string>;\n}\n\nexport interface FinishOptions {\n output: string;\n properties?: Record<string, string>;\n}\n\n/** A manual tool span the caller drives explicitly. */\nexport interface ToolSpan {\n setInput(input: unknown): void;\n setOutput(output: unknown): void;\n setError(error: Error | string): void;\n end(): void;\n}\n\n
|
|
1
|
+
{"version":3,"sources":["../../tracing/types.ts"],"sourcesContent":["/**\n * Morph Tracing — public types.\n *\n * Morph Tracing instruments the top AI SDKs (OpenAI, Anthropic, Vercel AI SDK,\n * Bedrock, Vertex, Cohere, Together, LangChain, LlamaIndex, …) and ships\n * OpenTelemetry spans to Morph. It is a thin, Morph-branded layer over\n * OpenLLMetry / Traceloop, exactly like `raindrop-ai` is.\n */\n\n/**\n * Modules to explicitly instrument. Pass the imported SDK module/constructor so\n * Traceloop patches the exact instance your app uses. If omitted, all supported\n * libraries are auto-instrumented.\n */\nexport interface InstrumentModules {\n openAI?: unknown;\n anthropic?: unknown;\n cohere?: unknown;\n bedrock?: unknown;\n google_vertexai?: unknown;\n google_aiplatform?: unknown;\n pinecone?: unknown;\n together?: unknown;\n langchain?: boolean;\n llamaIndex?: unknown;\n chromadb?: unknown;\n qdrant?: unknown;\n mcp?: unknown;\n [key: string]: unknown;\n}\n\nexport interface MorphTracingConfig {\n /**\n * Morph API key. Defaults to `process.env.MORPH_API_KEY`. Sent as\n * `Authorization: Bearer <apiKey>` to the trace ingest endpoint.\n */\n apiKey?: string;\n /**\n * Base URL for the Morph ingest API. Traces are POSTed to `${baseUrl}/v1/traces`.\n * Defaults to `process.env.MORPH_TRACES_URL` then `https://api.morphllm.com`.\n */\n baseUrl?: string;\n /** Service/app name attached to every span. Defaults to the host package name. */\n appName?: string;\n /**\n * When true, the SDK initializes nothing and ships nothing. Useful for tests\n * and local/dev. Defaults to false.\n */\n disabled?: boolean;\n /**\n * Send spans immediately instead of batching. Defaults to true outside\n * production (`NODE_ENV !== 'production'`) so local runs flush instantly.\n */\n disableBatching?: boolean;\n /**\n * Capture prompt/response content on spans. Set false for zero-data-retention.\n * Defaults to true.\n */\n traceContent?: boolean;\n /** Explicit modules to instrument. Omit to auto-instrument everything. */\n instrumentModules?: InstrumentModules;\n /**\n * Set true when you run your own OpenTelemetry NodeSDK. Morph will not start\n * its own SDK; instead use `getInstrumentations()` and `createSpanProcessor()`.\n */\n useExternalOtel?: boolean;\n /** Extra headers merged onto the OTLP exporter request. */\n headers?: Record<string, string>;\n /** Verbose `[morph-tracing]` logging. Defaults to `MORPH_TRACING_DEBUG=1`. */\n debug?: boolean;\n}\n\n/** Identity + content for a single traced AI interaction. */\nexport interface TraceContext {\n /** Stable identifier for the interaction; auto-generated if omitted. */\n eventId?: string;\n /** End-user identifier. */\n userId?: string;\n /** Conversation/session identifier grouping related interactions. */\n convoId?: string;\n /** Event name (defaults to \"ai_generation\" on the backend). */\n event?: string;\n /** User input for this interaction. */\n input?: string;\n /** Arbitrary string metadata propagated onto spans. */\n properties?: Record<string, string>;\n}\n\nexport interface SpanParams {\n name: string;\n properties?: Record<string, string>;\n}\n\nexport interface ToolParams {\n name: string;\n version?: number;\n properties?: Record<string, string>;\n}\n\n/** Record a tool invocation that has already completed. */\nexport interface TrackToolParams {\n name: string;\n input?: unknown;\n output?: unknown;\n durationMs?: number;\n error?: Error | string;\n properties?: Record<string, string>;\n}\n\nexport interface FinishOptions {\n output: string;\n properties?: Record<string, string>;\n}\n\n/** A manual tool span the caller drives explicitly. */\nexport interface ToolSpan {\n setInput(input: unknown): void;\n setOutput(output: unknown): void;\n setError(error: Error | string): void;\n end(): void;\n}\n\n/** Metadata payload for the Vercel AI SDK `experimental_telemetry.metadata`. */\nexport interface MetadataOptions {\n userId: string;\n convoId?: string;\n eventName?: string;\n eventId?: string;\n /** Custom tags, e.g. { source: \"support-bot\" } → association.properties.source */\n properties?: Record<string, string>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
package/dist/tracing/types.d.ts
CHANGED
|
@@ -111,19 +111,6 @@ interface ToolSpan {
|
|
|
111
111
|
setError(error: Error | string): void;
|
|
112
112
|
end(): void;
|
|
113
113
|
}
|
|
114
|
-
/**
|
|
115
|
-
* Feedback signal attached to an interaction by `eventId` — a good/bad relabel (the thumb
|
|
116
|
-
* the user clicked), with an optional freeform comment and an optional corrected label.
|
|
117
|
-
*/
|
|
118
|
-
type SignalEvent = {
|
|
119
|
-
eventId: string;
|
|
120
|
-
/** The thumb: "good" 👍 or "bad" 👎. */
|
|
121
|
-
verdict: 'good' | 'bad';
|
|
122
|
-
/** Optional freeform note from the user. */
|
|
123
|
-
comment?: string;
|
|
124
|
-
/** The label that *should* have been predicted — strong training signal for classifiers. */
|
|
125
|
-
correctedLabel?: string;
|
|
126
|
-
};
|
|
127
114
|
/** Metadata payload for the Vercel AI SDK `experimental_telemetry.metadata`. */
|
|
128
115
|
interface MetadataOptions {
|
|
129
116
|
userId: string;
|
|
@@ -134,4 +121,4 @@ interface MetadataOptions {
|
|
|
134
121
|
properties?: Record<string, string>;
|
|
135
122
|
}
|
|
136
123
|
|
|
137
|
-
export type { FinishOptions, InstrumentModules, MetadataOptions, MorphTracingConfig,
|
|
124
|
+
export type { FinishOptions, InstrumentModules, MetadataOptions, MorphTracingConfig, SpanParams, ToolParams, ToolSpan, TraceContext, TrackToolParams };
|
package/dist/version.cjs
CHANGED
|
@@ -27,7 +27,7 @@ module.exports = __toCommonJS(version_exports);
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@morphllm/morphsdk",
|
|
30
|
-
version: "0.2.
|
|
30
|
+
version: "0.2.184",
|
|
31
31
|
description: "TypeScript SDK and CLI for Morph Fast Apply integration",
|
|
32
32
|
type: "module",
|
|
33
33
|
main: "./dist/index.cjs",
|
|
@@ -204,7 +204,7 @@ var package_default = {
|
|
|
204
204
|
"!dist/**/*.test.*"
|
|
205
205
|
],
|
|
206
206
|
scripts: {
|
|
207
|
-
build: "tsup version.ts index.ts edge.ts client.ts core/index.ts core/client.ts core/resource.ts core/error.ts tools/index.ts tools/fastapply/index.ts tools/fastapply/core.ts tools/fastapply/apply.ts tools/fastapply/types.ts tools/fastapply/prompts.ts tools/fastapply/anthropic.ts tools/fastapply/openai.ts tools/fastapply/vercel.ts tools/codebase_search/index.ts tools/codebase_search/core.ts tools/codebase_search/types.ts tools/codebase_search/prompts.ts tools/codebase_search/anthropic.ts tools/codebase_search/openai.ts tools/codebase_search/vercel.ts tools/warp_grep/index.ts tools/warp_grep/client.ts tools/warp_grep/openai.ts tools/warp_grep/anthropic.ts tools/warp_grep/vercel.ts tools/warp_grep/gemini.ts tools/warp_grep/harness.ts tools/warp_grep/agent/config.ts tools/warp_grep/agent/parser.ts tools/warp_grep/agent/runner.ts tools/warp_grep/agent/types.ts tools/warp_grep/agent/formatter.ts tools/warp_grep/providers/types.ts tools/warp_grep/providers/local.ts tools/warp_grep/providers/remote.ts tools/warp_grep/providers/code_storage_http.ts tools/warp_grep/tools/grep.ts tools/warp_grep/tools/analyse.ts tools/warp_grep/tools/read.ts tools/warp_grep/tools/finish.ts tools/warp_grep/utils/paths.ts tools/warp_grep/utils/github.ts tools/warp_grep/utils/ripgrep.ts tools/warp_grep/utils/format.ts tools/warp_grep/utils/files.ts git/index.ts git/client.ts git/config.ts git/types.ts tools/browser/index.ts tools/browser/core.ts tools/browser/types.ts tools/browser/prompts.ts tools/browser/anthropic.ts tools/browser/openai.ts tools/browser/vercel.ts tools/browser/live.ts tools/browser/errors.ts tools/browser/profiles/index.ts tools/browser/profiles/core.ts tools/browser/profiles/types.ts modelrouter/index.ts modelrouter/core.ts modelrouter/types.ts tools/compact/index.ts tools/compact/core.ts tools/compact/types.ts tools/reflex/index.ts tools/reflex/core.ts tools/reflex/types.ts tools/utils/resilience.ts subagents/index.ts subagents/types.ts subagents/prompts.ts subagents/vercel.ts subagents/anthropic.ts tracing/index.ts tracing/core.ts tracing/interaction.ts tracing/otel.ts tracing/
|
|
207
|
+
build: "tsup version.ts index.ts edge.ts client.ts core/index.ts core/client.ts core/resource.ts core/error.ts tools/index.ts tools/fastapply/index.ts tools/fastapply/core.ts tools/fastapply/apply.ts tools/fastapply/types.ts tools/fastapply/prompts.ts tools/fastapply/anthropic.ts tools/fastapply/openai.ts tools/fastapply/vercel.ts tools/codebase_search/index.ts tools/codebase_search/core.ts tools/codebase_search/types.ts tools/codebase_search/prompts.ts tools/codebase_search/anthropic.ts tools/codebase_search/openai.ts tools/codebase_search/vercel.ts tools/warp_grep/index.ts tools/warp_grep/client.ts tools/warp_grep/openai.ts tools/warp_grep/anthropic.ts tools/warp_grep/vercel.ts tools/warp_grep/gemini.ts tools/warp_grep/harness.ts tools/warp_grep/agent/config.ts tools/warp_grep/agent/parser.ts tools/warp_grep/agent/runner.ts tools/warp_grep/agent/types.ts tools/warp_grep/agent/formatter.ts tools/warp_grep/providers/types.ts tools/warp_grep/providers/local.ts tools/warp_grep/providers/remote.ts tools/warp_grep/providers/code_storage_http.ts tools/warp_grep/tools/grep.ts tools/warp_grep/tools/analyse.ts tools/warp_grep/tools/read.ts tools/warp_grep/tools/finish.ts tools/warp_grep/utils/paths.ts tools/warp_grep/utils/github.ts tools/warp_grep/utils/ripgrep.ts tools/warp_grep/utils/format.ts tools/warp_grep/utils/files.ts git/index.ts git/client.ts git/config.ts git/types.ts tools/browser/index.ts tools/browser/core.ts tools/browser/types.ts tools/browser/prompts.ts tools/browser/anthropic.ts tools/browser/openai.ts tools/browser/vercel.ts tools/browser/live.ts tools/browser/errors.ts tools/browser/profiles/index.ts tools/browser/profiles/core.ts tools/browser/profiles/types.ts modelrouter/index.ts modelrouter/core.ts modelrouter/types.ts tools/compact/index.ts tools/compact/core.ts tools/compact/types.ts tools/reflex/index.ts tools/reflex/core.ts tools/reflex/types.ts tools/utils/resilience.ts subagents/index.ts subagents/types.ts subagents/prompts.ts subagents/vercel.ts subagents/anthropic.ts tracing/index.ts tracing/core.ts tracing/interaction.ts tracing/otel.ts tracing/types.ts --format esm,cjs --sourcemap --clean --dts --dts-resolve",
|
|
208
208
|
prepare: "npm run build",
|
|
209
209
|
typecheck: "tsc --noEmit",
|
|
210
210
|
lint: "eslint .",
|