@uselemma/tracing 2.17.0 → 3.0.1
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/README.md +33 -23
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/span-helpers.d.ts +50 -0
- package/dist/span-helpers.d.ts.map +1 -0
- package/dist/span-helpers.js +92 -0
- package/dist/span-helpers.js.map +1 -0
- package/dist/trace-wrapper.d.ts +70 -21
- package/dist/trace-wrapper.d.ts.map +1 -1
- package/dist/trace-wrapper.js +62 -26
- package/dist/trace-wrapper.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,40 +20,49 @@ import { registerOTel } from "@uselemma/tracing";
|
|
|
20
20
|
registerOTel();
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
You can also enable experiment mode globally for the process:
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
import { enableExperimentMode } from "@uselemma/tracing";
|
|
27
|
-
|
|
28
|
-
enableExperimentMode();
|
|
29
|
-
```
|
|
30
|
-
|
|
31
23
|
### 2. Wrap your agent
|
|
32
24
|
|
|
33
|
-
`
|
|
34
|
-
- `ai.agent.name`
|
|
35
|
-
- `lemma.run_id`
|
|
36
|
-
- `lemma.is_experiment`
|
|
37
|
-
- `lemma.thread_id` (when `threadId` is passed at invocation time)
|
|
25
|
+
`agent` creates a root OpenTelemetry span named `ai.agent.run`. Return a value from the wrapped function — the wrapper auto-captures it as `ai.agent.output` and closes the span automatically.
|
|
38
26
|
|
|
39
27
|
```typescript
|
|
40
|
-
import {
|
|
28
|
+
import { agent } from "@uselemma/tracing";
|
|
41
29
|
|
|
42
|
-
const
|
|
30
|
+
const myAgent = agent(
|
|
43
31
|
"my-agent",
|
|
44
|
-
async (
|
|
45
|
-
const result = await doWork(userMessage);
|
|
46
|
-
|
|
47
|
-
return result;
|
|
32
|
+
async (input: { userMessage: string }) => {
|
|
33
|
+
const result = await doWork(input.userMessage);
|
|
34
|
+
return result; // wrapper auto-captures output and closes the span
|
|
48
35
|
},
|
|
49
36
|
);
|
|
50
37
|
|
|
51
|
-
const { result, runId } = await
|
|
52
|
-
{ userMessage },
|
|
53
|
-
{ threadId: "thread_123",
|
|
38
|
+
const { result, runId } = await myAgent(
|
|
39
|
+
{ userMessage: "hello" },
|
|
40
|
+
{ threadId: "thread_123" }, // optional: link multi-turn runs
|
|
54
41
|
);
|
|
55
42
|
```
|
|
56
43
|
|
|
44
|
+
### 3. Add child spans (optional)
|
|
45
|
+
|
|
46
|
+
Use the typed helpers to add spans for internal functions:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { agent, tool, retrieval, llm, trace } from "@uselemma/tracing";
|
|
50
|
+
|
|
51
|
+
const search = retrieval("vector-search", async (query: string) => {
|
|
52
|
+
return vectorDB.search(query, { topK: 5 });
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const lookupOrder = tool("lookup-order", async (orderId: string) => {
|
|
56
|
+
return db.orders.findById(orderId);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const agent = agent("rag-agent", async (input: string) => {
|
|
60
|
+
const docs = await search(input); // retrieval.vector-search span
|
|
61
|
+
const context = docs.join("\n");
|
|
62
|
+
return generateAnswer(context, input);
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
57
66
|
## Export Behavior
|
|
58
67
|
|
|
59
68
|
- Spans are exported in run-specific batches keyed by `lemma.run_id`.
|
|
@@ -72,8 +81,9 @@ Both are required unless passed explicitly to `registerOTel()`.
|
|
|
72
81
|
|
|
73
82
|
## Documentation
|
|
74
83
|
|
|
84
|
+
- [Quickstart](https://docs.uselemma.ai/getting-started/quickstart) — first trace in 2 minutes
|
|
75
85
|
- [Tracing Overview](https://docs.uselemma.ai/tracing/overview) — concepts, API reference, and usage patterns
|
|
76
|
-
- [Vercel AI SDK
|
|
86
|
+
- [Vercel AI SDK](https://docs.uselemma.ai/integrations/vercel-ai-sdk) — framework setup, streaming, and examples
|
|
77
87
|
|
|
78
88
|
## License
|
|
79
89
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { registerOTel, createLemmaSpanProcessor, type LemmaOTelOptions, type RegisterOTelOptions, type CreateLemmaSpanProcessorOptions, } from "./register";
|
|
2
2
|
export { enableExperimentMode, disableExperimentMode, isExperimentModeEnabled, } from "./experiment-mode";
|
|
3
3
|
export { enableDebugMode, disableDebugMode, isDebugModeEnabled, } from "./debug-mode";
|
|
4
|
-
export {
|
|
4
|
+
export { agent, wrapAgent, // @deprecated — use agent instead
|
|
5
|
+
type TraceContext, type WrapAgentOptions, type WrapRunOptions, } from "./trace-wrapper";
|
|
6
|
+
export { trace, tool, llm, retrieval, } from "./span-helpers";
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,GACrC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,+BAA+B,GACrC,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,EACL,SAAS,EAAE,kCAAkC;AAC7C,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,EACL,IAAI,EACJ,GAAG,EACH,SAAS,GACV,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.wrapAgent = exports.isDebugModeEnabled = exports.disableDebugMode = exports.enableDebugMode = exports.isExperimentModeEnabled = exports.disableExperimentMode = exports.enableExperimentMode = exports.createLemmaSpanProcessor = exports.registerOTel = void 0;
|
|
3
|
+
exports.retrieval = exports.llm = exports.tool = exports.trace = exports.wrapAgent = exports.agent = exports.isDebugModeEnabled = exports.disableDebugMode = exports.enableDebugMode = exports.isExperimentModeEnabled = exports.disableExperimentMode = exports.enableExperimentMode = exports.createLemmaSpanProcessor = exports.registerOTel = void 0;
|
|
4
4
|
var register_1 = require("./register");
|
|
5
5
|
Object.defineProperty(exports, "registerOTel", { enumerable: true, get: function () { return register_1.registerOTel; } });
|
|
6
6
|
Object.defineProperty(exports, "createLemmaSpanProcessor", { enumerable: true, get: function () { return register_1.createLemmaSpanProcessor; } });
|
|
@@ -13,5 +13,11 @@ Object.defineProperty(exports, "enableDebugMode", { enumerable: true, get: funct
|
|
|
13
13
|
Object.defineProperty(exports, "disableDebugMode", { enumerable: true, get: function () { return debug_mode_1.disableDebugMode; } });
|
|
14
14
|
Object.defineProperty(exports, "isDebugModeEnabled", { enumerable: true, get: function () { return debug_mode_1.isDebugModeEnabled; } });
|
|
15
15
|
var trace_wrapper_1 = require("./trace-wrapper");
|
|
16
|
+
Object.defineProperty(exports, "agent", { enumerable: true, get: function () { return trace_wrapper_1.agent; } });
|
|
16
17
|
Object.defineProperty(exports, "wrapAgent", { enumerable: true, get: function () { return trace_wrapper_1.wrapAgent; } });
|
|
18
|
+
var span_helpers_1 = require("./span-helpers");
|
|
19
|
+
Object.defineProperty(exports, "trace", { enumerable: true, get: function () { return span_helpers_1.trace; } });
|
|
20
|
+
Object.defineProperty(exports, "tool", { enumerable: true, get: function () { return span_helpers_1.tool; } });
|
|
21
|
+
Object.defineProperty(exports, "llm", { enumerable: true, get: function () { return span_helpers_1.llm; } });
|
|
22
|
+
Object.defineProperty(exports, "retrieval", { enumerable: true, get: function () { return span_helpers_1.retrieval; } });
|
|
17
23
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAMoB;AALlB,wGAAA,YAAY,OAAA;AACZ,oHAAA,wBAAwB,OAAA;AAK1B,qDAI2B;AAHzB,uHAAA,oBAAoB,OAAA;AACpB,wHAAA,qBAAqB,OAAA;AACrB,0HAAA,uBAAuB,OAAA;AAEzB,2CAIsB;AAHpB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAEpB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAMoB;AALlB,wGAAA,YAAY,OAAA;AACZ,oHAAA,wBAAwB,OAAA;AAK1B,qDAI2B;AAHzB,uHAAA,oBAAoB,OAAA;AACpB,wHAAA,qBAAqB,OAAA;AACrB,0HAAA,uBAAuB,OAAA;AAEzB,2CAIsB;AAHpB,6GAAA,eAAe,OAAA;AACf,8GAAA,gBAAgB,OAAA;AAChB,gHAAA,kBAAkB,OAAA;AAEpB,iDAMyB;AALvB,sGAAA,KAAK,OAAA;AACL,0GAAA,SAAS,OAAA;AAKX,+CAKwB;AAJtB,qGAAA,KAAK,OAAA;AACL,oGAAA,IAAI,OAAA;AACJ,mGAAA,GAAG,OAAA;AACH,yGAAA,SAAS,OAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a function with a child span under the current active context.
|
|
3
|
+
*
|
|
4
|
+
* Use this for any internal function you want to appear in the trace — tool
|
|
5
|
+
* implementations, retrieval calls, preprocessing steps, etc.
|
|
6
|
+
*
|
|
7
|
+
* @param name - Span name shown in the Lemma trace view.
|
|
8
|
+
* @param fn - Function to wrap. Receives the same input as the returned wrapper.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* const formatOutput = trace("format-output", async (raw: string) => {
|
|
12
|
+
* return raw.trim().toLowerCase();
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // Inside an agent() handler:
|
|
16
|
+
* const formatted = await formatOutput(rawText);
|
|
17
|
+
*/
|
|
18
|
+
export declare function trace<Input = unknown, Output = unknown>(name: string, fn: (input: Input) => Output | Promise<Output>): (input: Input) => Promise<Output>;
|
|
19
|
+
/**
|
|
20
|
+
* Wraps a tool function with a child span named `tool.<name>`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const lookupOrder = tool("lookup-order", async (orderId: string) => {
|
|
24
|
+
* return db.orders.findById(orderId);
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
export declare function tool<Input = unknown, Output = unknown>(name: string, fn: (input: Input) => Output | Promise<Output>): (input: Input) => Promise<Output>;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps an LLM call with a child span named `llm.<name>`.
|
|
30
|
+
*
|
|
31
|
+
* Prefer provider instrumentation (OpenInference) for automatic LLM spans
|
|
32
|
+
* with prompt/completion/token attributes. Use this helper for custom or
|
|
33
|
+
* lightly-instrumented models.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const generate = llm("gpt-4o", async (prompt: string) => {
|
|
37
|
+
* return openai.chat.completions.create({ ... });
|
|
38
|
+
* });
|
|
39
|
+
*/
|
|
40
|
+
export declare function llm<Input = unknown, Output = unknown>(name: string, fn: (input: Input) => Output | Promise<Output>): (input: Input) => Promise<Output>;
|
|
41
|
+
/**
|
|
42
|
+
* Wraps a retrieval function with a child span named `retrieval.<name>`.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const search = retrieval("vector-search", async (query: string) => {
|
|
46
|
+
* return vectorDB.search(query, { topK: 5 });
|
|
47
|
+
* });
|
|
48
|
+
*/
|
|
49
|
+
export declare function retrieval<Input = unknown, Output = unknown>(name: string, fn: (input: Input) => Output | Promise<Output>): (input: Input) => Promise<Output>;
|
|
50
|
+
//# sourceMappingURL=span-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"span-helpers.d.ts","sourceRoot":"","sources":["../src/span-helpers.ts"],"names":[],"mappings":"AAiCA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,EACrD,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC7C,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAEnC;AAED;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,EACpD,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC7C,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAEnC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,GAAG,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,EACnD,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC7C,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAEnC;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,EACzD,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC7C,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,CAEnC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.trace = trace;
|
|
4
|
+
exports.tool = tool;
|
|
5
|
+
exports.llm = llm;
|
|
6
|
+
exports.retrieval = retrieval;
|
|
7
|
+
const api_1 = require("@opentelemetry/api");
|
|
8
|
+
/**
|
|
9
|
+
* Core helper: wraps `fn` so every call runs inside a child span named
|
|
10
|
+
* `spanName` under the currently active context. Unlike `wrapAgent`, this
|
|
11
|
+
* does NOT create a new trace root — it adds a child span to whatever span
|
|
12
|
+
* is currently active.
|
|
13
|
+
*
|
|
14
|
+
* The span ends when the function returns (or throws). Return values are
|
|
15
|
+
* passed through unchanged.
|
|
16
|
+
*/
|
|
17
|
+
function spanHelper(spanName, fn) {
|
|
18
|
+
return async function (input) {
|
|
19
|
+
const tracer = api_1.trace.getTracer("lemma");
|
|
20
|
+
return tracer.startActiveSpan(spanName, async (span) => {
|
|
21
|
+
try {
|
|
22
|
+
const result = await fn(input);
|
|
23
|
+
span.end();
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
span.recordException(err);
|
|
28
|
+
span.setStatus({ code: 2 }); // SpanStatusCode.ERROR
|
|
29
|
+
span.end();
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Wraps a function with a child span under the current active context.
|
|
37
|
+
*
|
|
38
|
+
* Use this for any internal function you want to appear in the trace — tool
|
|
39
|
+
* implementations, retrieval calls, preprocessing steps, etc.
|
|
40
|
+
*
|
|
41
|
+
* @param name - Span name shown in the Lemma trace view.
|
|
42
|
+
* @param fn - Function to wrap. Receives the same input as the returned wrapper.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const formatOutput = trace("format-output", async (raw: string) => {
|
|
46
|
+
* return raw.trim().toLowerCase();
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Inside an agent() handler:
|
|
50
|
+
* const formatted = await formatOutput(rawText);
|
|
51
|
+
*/
|
|
52
|
+
function trace(name, fn) {
|
|
53
|
+
return spanHelper(name, fn);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Wraps a tool function with a child span named `tool.<name>`.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const lookupOrder = tool("lookup-order", async (orderId: string) => {
|
|
60
|
+
* return db.orders.findById(orderId);
|
|
61
|
+
* });
|
|
62
|
+
*/
|
|
63
|
+
function tool(name, fn) {
|
|
64
|
+
return spanHelper(`tool.${name}`, fn);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Wraps an LLM call with a child span named `llm.<name>`.
|
|
68
|
+
*
|
|
69
|
+
* Prefer provider instrumentation (OpenInference) for automatic LLM spans
|
|
70
|
+
* with prompt/completion/token attributes. Use this helper for custom or
|
|
71
|
+
* lightly-instrumented models.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* const generate = llm("gpt-4o", async (prompt: string) => {
|
|
75
|
+
* return openai.chat.completions.create({ ... });
|
|
76
|
+
* });
|
|
77
|
+
*/
|
|
78
|
+
function llm(name, fn) {
|
|
79
|
+
return spanHelper(`llm.${name}`, fn);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Wraps a retrieval function with a child span named `retrieval.<name>`.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const search = retrieval("vector-search", async (query: string) => {
|
|
86
|
+
* return vectorDB.search(query, { topK: 5 });
|
|
87
|
+
* });
|
|
88
|
+
*/
|
|
89
|
+
function retrieval(name, fn) {
|
|
90
|
+
return spanHelper(`retrieval.${name}`, fn);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=span-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"span-helpers.js","sourceRoot":"","sources":["../src/span-helpers.ts"],"names":[],"mappings":";;AAkDA,sBAKC;AAUD,oBAKC;AAcD,kBAKC;AAUD,8BAKC;AAxGD,4CAAwD;AAGxD;;;;;;;;GAQG;AACH,SAAS,UAAU,CACjB,QAAgB,EAChB,EAA8C;IAE9C,OAAO,KAAK,WAAW,KAAY;QACjC,MAAM,MAAM,GAAG,WAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5C,OAAO,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAU,EAAE,EAAE;YAC3D,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,eAAe,CAAC,GAAY,CAAC,CAAC;gBACnC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB;gBACpD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACX,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,KAAK,CACnB,IAAY,EACZ,EAA8C;IAE9C,OAAO,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,IAAI,CAClB,IAAY,EACZ,EAA8C;IAE9C,OAAO,UAAU,CAAC,QAAQ,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,GAAG,CACjB,IAAY,EACZ,EAA8C;IAE9C,OAAO,UAAU,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,SAAS,CACvB,IAAY,EACZ,EAA8C;IAE9C,OAAO,UAAU,CAAC,aAAa,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/trace-wrapper.d.ts
CHANGED
|
@@ -5,17 +5,49 @@ export type TraceContext = {
|
|
|
5
5
|
/** Unique identifier for this agent run. */
|
|
6
6
|
runId: string;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Override the run output and close the span immediately.
|
|
9
|
+
*
|
|
10
|
+
* In non-streaming agents, `complete()` is **optional** — the wrapper
|
|
11
|
+
* automatically captures the return value as `ai.agent.output` and closes
|
|
12
|
+
* the span when the function returns. Call it explicitly only when you need
|
|
13
|
+
* to record a different output than the return value, or close the span
|
|
14
|
+
* before the function exits.
|
|
15
|
+
*
|
|
16
|
+
* In streaming agents (`{ streaming: true }`), `complete()` is **required**
|
|
17
|
+
* — call it inside the stream's `onFinish` callback once the full output is
|
|
18
|
+
* assembled.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent: the first call wins, subsequent calls are no-ops.
|
|
21
|
+
*/
|
|
22
|
+
complete: (result?: unknown) => void;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Use {@link complete} instead.
|
|
11
25
|
*/
|
|
12
26
|
onComplete: (result: unknown) => void;
|
|
13
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Record an error on the span and mark the run as failed.
|
|
29
|
+
* Does not close the span — the wrapper handles closing on return or error.
|
|
30
|
+
*/
|
|
31
|
+
fail: (error: unknown) => void;
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated Use {@link fail} instead.
|
|
34
|
+
*/
|
|
14
35
|
recordError: (error: unknown) => void;
|
|
15
36
|
};
|
|
16
37
|
export type WrapAgentOptions = {
|
|
17
38
|
/** Mark this run as an experiment in Lemma. */
|
|
18
39
|
isExperiment?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Set to `true` for agents that return a streaming response before the
|
|
42
|
+
* full output is known.
|
|
43
|
+
*
|
|
44
|
+
* When `true`, the wrapper does **not** auto-close the span on function
|
|
45
|
+
* return. You must call `ctx.complete(output)` inside the stream's
|
|
46
|
+
* `onFinish` callback once the full output is assembled.
|
|
47
|
+
*
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
streaming?: boolean;
|
|
19
51
|
};
|
|
20
52
|
export type WrapRunOptions = {
|
|
21
53
|
/** Optional thread identifier for this invocation. */
|
|
@@ -27,32 +59,49 @@ export type WrapRunOptions = {
|
|
|
27
59
|
* Wraps an agent function with OpenTelemetry tracing, automatically creating
|
|
28
60
|
* a span for the agent run and providing a `TraceContext` to the wrapped function.
|
|
29
61
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
62
|
+
* **Non-streaming (default):** simply return a value from the wrapped function.
|
|
63
|
+
* The wrapper captures it as `ai.agent.output` and closes the span automatically.
|
|
64
|
+
* No call to `ctx.complete()` is needed.
|
|
65
|
+
*
|
|
66
|
+
* **Streaming:** pass `{ streaming: true }` as the third argument. The wrapper
|
|
67
|
+
* will not auto-close the span on return; call `ctx.complete(output)` inside
|
|
68
|
+
* the stream's `onFinish` callback once the full output is assembled.
|
|
32
69
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Non-streaming — just return a value
|
|
72
|
+
* const myAgent = agent('my-agent', async (input: string) => {
|
|
73
|
+
* const { text } = await generateText({
|
|
74
|
+
* model: openai('gpt-4o'), prompt: input,
|
|
75
|
+
* experimental_telemetry: { isEnabled: true },
|
|
76
|
+
* });
|
|
77
|
+
* return text; // wrapper auto-captures and closes the span
|
|
78
|
+
* });
|
|
36
79
|
*
|
|
37
80
|
* @example
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
81
|
+
* // Streaming — opt into manual lifecycle
|
|
82
|
+
* const streamingAgent = agent('streaming-agent', async (input: string, ctx) => {
|
|
83
|
+
* const result = await streamText({
|
|
84
|
+
* model: openai('gpt-4o'), prompt: input,
|
|
85
|
+
* experimental_telemetry: { isEnabled: true },
|
|
86
|
+
* onFinish({ text }) { ctx.complete(text); },
|
|
87
|
+
* });
|
|
88
|
+
* return result.toDataStreamResponse();
|
|
89
|
+
* }, { streaming: true });
|
|
46
90
|
*
|
|
47
91
|
* @param agentName - Human-readable agent name recorded as `ai.agent.name`.
|
|
48
|
-
* @param fn - The agent function to wrap. Receives
|
|
92
|
+
* @param fn - The agent function to wrap. Receives the call-time input as its
|
|
93
|
+
* first argument and an optional {@link TraceContext} as its second.
|
|
49
94
|
* @param options - Configuration for the agent trace.
|
|
50
|
-
* @
|
|
51
|
-
*
|
|
95
|
+
* @returns An async function that accepts an `input`, executes `fn` inside a
|
|
96
|
+
* traced context, and returns `{ result, runId, span }`.
|
|
52
97
|
*/
|
|
53
|
-
export declare function
|
|
98
|
+
export declare function agent<Input = unknown>(agentName: string, fn: (input: Input, traceContext: TraceContext) => any, options?: WrapAgentOptions): (this: any, input: Input, runOptions?: WrapRunOptions) => Promise<{
|
|
54
99
|
result: any;
|
|
55
100
|
runId: string;
|
|
56
101
|
span: Span;
|
|
57
102
|
}>;
|
|
103
|
+
/**
|
|
104
|
+
* @deprecated Use {@link agent} instead. `wrapAgent` will be removed in a future major version.
|
|
105
|
+
*/
|
|
106
|
+
export declare const wrapAgent: typeof agent;
|
|
58
107
|
//# sourceMappingURL=trace-wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-wrapper.d.ts","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAKxE,MAAM,MAAM,YAAY,GAAG;IACzB,wDAAwD;IACxD,IAAI,EAAE,IAAI,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd
|
|
1
|
+
{"version":3,"file":"trace-wrapper.d.ts","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAKxE,MAAM,MAAM,YAAY,GAAG;IACzB,wDAAwD;IACxD,IAAI,EAAE,IAAI,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;OAcG;IACH,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC;;OAEG;IACH,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/B;;OAEG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAkBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,KAAK,CAAC,KAAK,GAAG,OAAO,EACnC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,KAAK,GAAG,EACrD,OAAO,CAAC,EAAE,gBAAgB,UAKlB,GAAG,SACF,KAAK,eACC,cAAc;;;;GAmF9B;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,cAAQ,CAAC"}
|
package/dist/trace-wrapper.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.wrapAgent =
|
|
3
|
+
exports.wrapAgent = void 0;
|
|
4
|
+
exports.agent = agent;
|
|
4
5
|
const api_1 = require("@opentelemetry/api");
|
|
5
6
|
const uuid_1 = require("uuid");
|
|
6
7
|
const debug_mode_1 = require("./debug-mode");
|
|
@@ -22,30 +23,44 @@ function normalizeThreadId(threadId) {
|
|
|
22
23
|
* Wraps an agent function with OpenTelemetry tracing, automatically creating
|
|
23
24
|
* a span for the agent run and providing a `TraceContext` to the wrapped function.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
26
|
+
* **Non-streaming (default):** simply return a value from the wrapped function.
|
|
27
|
+
* The wrapper captures it as `ai.agent.output` and closes the span automatically.
|
|
28
|
+
* No call to `ctx.complete()` is needed.
|
|
27
29
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* **Streaming:** pass `{ streaming: true }` as the third argument. The wrapper
|
|
31
|
+
* will not auto-close the span on return; call `ctx.complete(output)` inside
|
|
32
|
+
* the stream's `onFinish` callback once the full output is assembled.
|
|
31
33
|
*
|
|
32
34
|
* @example
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* }
|
|
39
|
-
*
|
|
40
|
-
*
|
|
35
|
+
* // Non-streaming — just return a value
|
|
36
|
+
* const myAgent = agent('my-agent', async (input: string) => {
|
|
37
|
+
* const { text } = await generateText({
|
|
38
|
+
* model: openai('gpt-4o'), prompt: input,
|
|
39
|
+
* experimental_telemetry: { isEnabled: true },
|
|
40
|
+
* });
|
|
41
|
+
* return text; // wrapper auto-captures and closes the span
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* // Streaming — opt into manual lifecycle
|
|
46
|
+
* const streamingAgent = agent('streaming-agent', async (input: string, ctx) => {
|
|
47
|
+
* const result = await streamText({
|
|
48
|
+
* model: openai('gpt-4o'), prompt: input,
|
|
49
|
+
* experimental_telemetry: { isEnabled: true },
|
|
50
|
+
* onFinish({ text }) { ctx.complete(text); },
|
|
51
|
+
* });
|
|
52
|
+
* return result.toDataStreamResponse();
|
|
53
|
+
* }, { streaming: true });
|
|
41
54
|
*
|
|
42
55
|
* @param agentName - Human-readable agent name recorded as `ai.agent.name`.
|
|
43
|
-
* @param fn - The agent function to wrap. Receives
|
|
56
|
+
* @param fn - The agent function to wrap. Receives the call-time input as its
|
|
57
|
+
* first argument and an optional {@link TraceContext} as its second.
|
|
44
58
|
* @param options - Configuration for the agent trace.
|
|
45
|
-
* @
|
|
46
|
-
*
|
|
59
|
+
* @returns An async function that accepts an `input`, executes `fn` inside a
|
|
60
|
+
* traced context, and returns `{ result, runId, span }`.
|
|
47
61
|
*/
|
|
48
|
-
function
|
|
62
|
+
function agent(agentName, fn, options) {
|
|
63
|
+
const streaming = options?.streaming ?? false;
|
|
49
64
|
const wrappedFunction = async function (input, runOptions) {
|
|
50
65
|
const tracer = api_1.trace.getTracer("lemma");
|
|
51
66
|
const runId = (0, uuid_1.v4)();
|
|
@@ -59,39 +74,60 @@ function wrapAgent(agentName, fn, options) {
|
|
|
59
74
|
if (threadId) {
|
|
60
75
|
attributes["lemma.thread_id"] = threadId;
|
|
61
76
|
}
|
|
62
|
-
const span = tracer.startSpan("ai.agent.run", {
|
|
63
|
-
attributes,
|
|
64
|
-
}, api_1.ROOT_CONTEXT);
|
|
77
|
+
const span = tracer.startSpan("ai.agent.run", { attributes }, api_1.ROOT_CONTEXT);
|
|
65
78
|
span.setAttribute("ai.agent.input", JSON.stringify(input) ?? "null");
|
|
66
79
|
(0, debug_mode_1.lemmaDebug)("trace-wrapper", "span started", { agentName, runId });
|
|
67
80
|
const ctx = api_1.trace.setSpan(api_1.ROOT_CONTEXT, span);
|
|
68
81
|
let outputSet = false;
|
|
69
82
|
try {
|
|
70
83
|
return await api_1.context.with(ctx, async () => {
|
|
71
|
-
const
|
|
84
|
+
const complete = (result) => {
|
|
72
85
|
if (outputSet)
|
|
73
86
|
return;
|
|
74
87
|
span.setAttribute("ai.agent.output", JSON.stringify(result) ?? "null");
|
|
75
88
|
outputSet = true;
|
|
76
89
|
span.end();
|
|
77
|
-
(0, debug_mode_1.lemmaDebug)("trace-wrapper", "
|
|
90
|
+
(0, debug_mode_1.lemmaDebug)("trace-wrapper", "complete called", { runId });
|
|
78
91
|
};
|
|
79
|
-
const
|
|
92
|
+
const fail = (error) => {
|
|
80
93
|
span.recordException(error instanceof Error ? error : new Error(String(error)));
|
|
81
94
|
span.setStatus({ code: 2 }); // SpanStatusCode.ERROR
|
|
82
95
|
};
|
|
83
|
-
const
|
|
96
|
+
const traceCtx = {
|
|
97
|
+
span,
|
|
98
|
+
runId,
|
|
99
|
+
complete,
|
|
100
|
+
onComplete: complete,
|
|
101
|
+
fail,
|
|
102
|
+
recordError: fail,
|
|
103
|
+
};
|
|
104
|
+
const result = await fn.call(this, input, traceCtx);
|
|
105
|
+
if (!streaming && !outputSet) {
|
|
106
|
+
complete(result);
|
|
107
|
+
}
|
|
108
|
+
else if (streaming && !outputSet) {
|
|
109
|
+
(0, debug_mode_1.lemmaDebug)("trace-wrapper", "streaming agent returned without complete()", { agentName, runId });
|
|
110
|
+
console.warn(`[lemma] Streaming agent "${agentName}" returned without calling ctx.complete(). ` +
|
|
111
|
+
`Call ctx.complete(output) inside the stream's onFinish callback to close the run span.`);
|
|
112
|
+
}
|
|
84
113
|
return { result, runId, span };
|
|
85
114
|
});
|
|
86
115
|
}
|
|
87
116
|
catch (err) {
|
|
88
117
|
span.recordException(err);
|
|
89
118
|
span.setStatus({ code: 2 }); // SpanStatusCode.ERROR
|
|
90
|
-
|
|
119
|
+
if (!outputSet) {
|
|
120
|
+
outputSet = true;
|
|
121
|
+
span.end();
|
|
122
|
+
}
|
|
91
123
|
(0, debug_mode_1.lemmaDebug)("trace-wrapper", "span ended on error", { runId, error: String(err) });
|
|
92
124
|
throw err;
|
|
93
125
|
}
|
|
94
126
|
};
|
|
95
127
|
return wrappedFunction;
|
|
96
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* @deprecated Use {@link agent} instead. `wrapAgent` will be removed in a future major version.
|
|
131
|
+
*/
|
|
132
|
+
exports.wrapAgent = agent;
|
|
97
133
|
//# sourceMappingURL=trace-wrapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace-wrapper.js","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"trace-wrapper.js","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"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"}
|