wrapAgent wraps your agent function with OpenTelemetry tracing, creating a top-level span that captures the full execution — inputs, outputs, timing, and any nested operations that happen inside it.
Basic Usage
import { wrapAgent } from "@uselemma/tracing";
export const callAgent = async (userMessage: string) => {
const wrappedFn = wrapAgent(
"my-agent",
async ({ onComplete }, input) => {
const result = await doWork(input.userMessage);
onComplete(result);
return result;
}
);
const { result, runId } = await wrappedFn({ userMessage });
return { result, runId };
};
from uselemma_tracing import TraceContext, wrap_agent
async def run_agent(ctx: TraceContext, input: dict):
result = await do_work(input["user_message"])
ctx.on_complete(result)
return result
async def call_agent(user_message: str):
wrapped = wrap_agent("my-agent", run_agent)
result, run_id, span = await wrapped({"user_message": user_message})
return result, run_id
Streaming
For streaming responses, set autoEndRoot: true so the RunBatchSpanProcessor automatically ends the root span when all direct child spans have finished. Call onComplete to record the output once the stream finishes, and recordError if something goes wrong.
import { wrapAgent } from "@uselemma/tracing";
export const callAgent = async (userMessage: string) => {
const wrappedFn = wrapAgent(
"my-agent",
async ({ onComplete, recordError }, input) => {
try {
const stream = await streamResponse(input.userMessage);
let fullResponse = "";
for await (const chunk of stream) {
fullResponse += chunk;
// stream to your client here
}
onComplete({ text: fullResponse });
return { text: fullResponse };
} catch (error) {
recordError(error);
throw error;
}
},
{ autoEndRoot: true }
);
const { result, runId } = await wrappedFn({ userMessage });
return { result, runId };
};
from uselemma_tracing import TraceContext, wrap_agent
async def run_agent(ctx: TraceContext, input: dict):
try:
stream = await stream_response(input["user_message"])
full_response = ""
async for chunk in stream:
full_response += chunk
# stream to your client here
ctx.on_complete(full_response)
return full_response
except Exception as err:
ctx.record_error(err)
raise
async def call_agent(user_message: str):
wrapped = wrap_agent("my-agent", run_agent, auto_end_root=True)
result, run_id, span = await wrapped({"user_message": user_message})
return result, run_id
API Reference
Parameters
wrapAgent(name, agentFn, options?)
| Parameter | Type | Description |
|---|
name | string | Agent identifier for filtering and grouping in the dashboard |
agentFn | (ctx: TraceContext, input: Input) => any | Your agent logic. Receives the call-time input as its second argument, which is recorded as the trace input |
options | object | Optional configuration (see below) |
Options| Field | Type | Default | Description |
|---|
isExperiment | boolean | false | Tag this run as an experiment |
autoEndRoot | boolean | false | If true, the RunBatchSpanProcessor automatically ends the root span when all direct child spans have ended. Useful for streaming where child spans outlive the wrapped function. |
Return Value| Field | Type | Description |
|---|
result | any | Your agent function’s return value |
runId | string | Unique identifier for this trace |
span | Span | The underlying OpenTelemetry span |
wrap_agent(name, fn, *, is_experiment, auto_end_root)
| Parameter | Type | Default | Description |
|---|
name | str | — | Agent identifier for filtering and grouping in the dashboard |
fn | Callable | — | Your agent logic. Receives the call-time input as its second argument, which is recorded as the trace input |
is_experiment | bool | False | Tag this run as an experiment |
auto_end_root | bool | False | If True, the RunBatchSpanProcessor automatically ends the root span when all direct child spans have ended. Useful for streaming where child spans outlive the wrapped function. |
Return ValueReturns a tuple of (result, run_id, span).| Field | Type | Description |
|---|
result | Any | Your agent function’s return value |
run_id | str | Unique identifier for this trace |
span | Span | The underlying OpenTelemetry span |
TraceContext
Your agent function always receives a TraceContext object as its first argument:
| Field | Description |
|---|
onComplete(result) / on_complete(result) | Records the agent’s output on the span. When autoEndRoot is false (the default), this also ends the root span and returns true. When autoEndRoot is true, this only records the output and returns false — the span is ended automatically by the processor when all direct children finish. |
recordError(error) / record_error(error) | Records the exception and marks the span as errored |
span | The underlying OpenTelemetry span for custom attributes or child spans |
runId / run_id | The unique run identifier |
When autoEndRoot is false (the default), you must call onComplete(result) to record the output and end the root span. When autoEndRoot is true, onComplete(result) only records the output — the RunBatchSpanProcessor ends the root span automatically once all direct child spans have ended.