Traced Wrappers¶
The traced wrappers are composition functions that intercept GeminiClient, ToolRegistry, and RetrievalService to emit spans automatically. They are fire-and-forget: tracing errors never break the primary operation.
Import¶
import {
createTracedGeminiClient,
createTracedToolRegistry,
createTracedRetrievalService,
} from "@modernpath/agent-framework";
createTracedGeminiClient¶
function createTracedGeminiClient(
inner: GeminiClient,
opts: TracedGeminiClientOpts,
): GeminiClient
Wraps a GeminiClient to emit LLM spans for generateContent and generateContentStream calls. All other methods delegate directly to the inner client.
TracedGeminiClientOpts¶
| Property | Type | Description |
|---|---|---|
getTraceContext | () => TraceContext \| undefined | Function that returns the current TraceContext (typically reads from AgentContext.metadata). |
model | string | Model name for span attributes (used in gen_ai.request.model). |
Span Details¶
For each LLM call, the wrapper records:
| Attribute | Description |
|---|---|
kind | "llm" |
name | "gemini.generateContent" or "gemini.generateContentStream" |
gen_ai.request.model | Model name |
gen_ai.usage.input_tokens | Input token count (non-streaming only) |
gen_ai.usage.output_tokens | Output token count (non-streaming only) |
gen_ai.request.temperature | Temperature setting |
gen_ai.request.max_tokens | Max output tokens |
gen_ai.system_instructions | System prompt (when captureContent is true) |
gen_ai.response.finish_reasons | Finish reason array |
When captureContent is true, the full prompt and response text are stored in input and output. When false, only lengths are recorded.
For streaming calls, chunks are accumulated and the full response text is written to the span on stream completion.
createTracedToolRegistry¶
function createTracedToolRegistry(
inner: ToolRegistry,
opts: TracedToolRegistryOpts,
): ToolRegistry
Wraps a ToolRegistry to emit tool spans for execute() calls. All other methods (register, has, list, getMetadata) delegate directly.
TracedToolRegistryOpts¶
| Property | Type | Description |
|---|---|---|
getTraceContext | () => TraceContext \| undefined | Function that returns the current TraceContext. |
Span Details¶
| Attribute | Description |
|---|---|
kind | "tool" |
name | "tool.<toolName>" |
toolType | "framework", "mcp", or "dynamic" (detected from metadata category) |
input | Full params (captureContent) or param keys only |
output | Full result (captureContent) or { hasResult: boolean } |
createTracedRetrievalService¶
function createTracedRetrievalService(
inner: RetrievalService,
opts: TracedRetrievalServiceOpts,
): RetrievalService
Wraps a RetrievalService to emit retrieval spans for search() calls. The resolveStoreName() method delegates directly.
TracedRetrievalServiceOpts¶
| Property | Type | Description |
|---|---|---|
getTraceContext | () => TraceContext \| undefined | Function that returns the current TraceContext. |
Span Details¶
| Attribute | Description |
|---|---|
kind | "retrieval" |
name | "retrieval.search" |
input | Query, store name, topK, metadataFilter (captureContent) or query length and store name |
output | Sources count, context length, source details with chunk previews (captureContent) or counts only |
Wiring Tracing¶
The typical pattern for wiring traced wrappers in an agent:
import {
InMemoryTraceStore,
createTracedGeminiClient,
createTracedToolRegistry,
createTracedRetrievalService,
TraceContext,
} from "@modernpath/agent-framework";
// Create trace store
const traceStore = new InMemoryTraceStore({ captureContent: true });
// Thread-local trace context (set per-execution by BaseAgent)
let currentTraceContext: TraceContext | undefined;
const getCtx = () => currentTraceContext;
// Wrap services
const tracedGemini = createTracedGeminiClient(geminiClient, {
getTraceContext: getCtx,
model: "gemini-2.5-flash",
});
const tracedTools = createTracedToolRegistry(toolRegistry, {
getTraceContext: getCtx,
});
const tracedRetrieval = createTracedRetrievalService(retrievalService, {
getTraceContext: getCtx,
});
// Use traced versions in your agent
class MyAgent extends BaseAgent {
constructor() {
super("MyAgent", "1.0.0", tracedTools, {
traceStore,
gemini: tracedGemini,
retrieval: tracedRetrieval,
});
}
protected async executeInternal(context: AgentContext): Promise<any> {
// All LLM calls, tool executions, and retrievals are automatically traced
const ragResult = await tracedRetrieval.search("query", "my-store");
const response = await tracedGemini.generateContent("Analyze this...");
return { answer: response.text };
}
}
Error Handling¶
All traced wrappers follow a fire-and-forget pattern:
- The primary operation (LLM call, tool execution, retrieval) always completes normally
- Span recording happens in a
.catch(() => {})block - If span recording fails (e.g., Firestore is down), the error is silently swallowed
- The primary operation result is always returned to the caller
This design ensures that tracing infrastructure issues never degrade agent functionality.
Related Pages¶
- TraceStore Interface -- where spans are persisted
- InMemoryTraceStore -- testing traced wrappers
- CostCalculator -- calculating costs from span token data