Skip to content

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:

  1. The primary operation (LLM call, tool execution, retrieval) always completes normally
  2. Span recording happens in a .catch(() => {}) block
  3. If span recording fails (e.g., Firestore is down), the error is silently swallowed
  4. The primary operation result is always returned to the caller

This design ensures that tracing infrastructure issues never degrade agent functionality.