Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentmark.co/llms.txt

Use this file to discover all available pages before exploring further.

AgentMark uses OpenTelemetry to collect distributed traces and metrics for your prompt executions. This page covers everything from basic setup to advanced tracing patterns.

Install the SDK

npm install @agentmark-ai/sdk

Initialize tracing

import { AgentMarkSDK } from "@agentmark-ai/sdk";
import { createAgentMarkClient, VercelAIModelRegistry } from "@agentmark-ai/ai-sdk-v5-adapter";
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";

const sdk = new AgentMarkSDK({
  apiKey: process.env.AGENTMARK_API_KEY,
  appId: process.env.AGENTMARK_APP_ID,
  baseUrl: process.env.AGENTMARK_BASE_URL  // defaults to https://api.agentmark.co
});

// Initialize tracing
const tracer = sdk.initTracing();

// Configure client
const modelRegistry = new VercelAIModelRegistry();
modelRegistry.registerProviders({ openai });

const client = createAgentMarkClient({
  loader: sdk.getApiLoader(),
  modelRegistry
});

// Load and run prompt with telemetry
const prompt = await client.loadTextPrompt("greeting.prompt.mdx");
const input = await prompt.format({
  props: { name: 'Alice' },
  telemetry: {
    isEnabled: true,
    functionId: "greeting-function",
    metadata: {
      userId: "123",
      environment: "production"
    }
  }
});

const result = await generateText(input);

// Shutdown tracer (only for short-running scripts)
await tracer.shutdown();
For local development with npx agentmark dev, traces are sent to http://localhost:9418 automatically. Pass disableBatch: true for short-running scripts:
const tracer = sdk.initTracing({ disableBatch: true });

Collected spans

AgentMark records these OpenTelemetry spans:
Span typeDescriptionKey attributes
ai.inferenceFull inference call lifecycleai.model.id, ai.prompt, ai.response.text, ai.usage.promptTokens, ai.usage.completionTokens
ai.toolCallIndividual tool executionsai.toolCall.name, ai.toolCall.args, ai.toolCall.result
ai.streamStreaming response metricsai.response.msToFirstChunk, ai.response.msToFinish, ai.response.avgCompletionTokensPerSecond

Span attributes

Each span contains detailed attributes: Model information: ai.model.id (e.g., "gpt-4o-mini"), ai.model.provider (e.g., "openai") Token usage: ai.usage.promptTokens, ai.usage.completionTokens Telemetry metadata: ai.telemetry.functionId, ai.telemetry.metadata.* Response details: ai.response.text, ai.response.toolCalls, ai.response.finishReason

Grouping operations into a span

Use span() (TypeScript) or span_context() (Python) to wrap a block of work as a single parent span. Nested SDK calls automatically attach as children.
import { span } from "@agentmark-ai/sdk";

const { result, traceId } = await span(
  { name: 'user-request-handler' },
  async (ctx) => {
    const prompt = await client.loadTextPrompt('handler.prompt.mdx');
    const input = await prompt.format({
      props: { query: 'What is AgentMark?' },
      telemetry: { isEnabled: true }
    });

    return await generateText(input);
  }
);

console.log('Trace ID:', traceId);
const output = await result;

SpanOptions

OptionTypeRequiredDescription
namestringYesName for the span
metadataRecord<string, string>NoCustom key-value metadata (strings only)
sessionIdstringNoGroup traces into a session
sessionNamestringNoHuman-readable session name
userIdstringNoAssociate trace with a user
datasetRunIdstringNoLink to a dataset run
datasetRunNamestringNoHuman-readable dataset run name
datasetItemNamestringNoSpecific dataset item name
datasetExpectedOutputstringNoExpected output for evaluation
datasetPathstringNoPath to the dataset file

SpanResult

interface SpanResult<T> {
  result: Promise<T>;  // The result of your callback (as a Promise)
  traceId: string;     // The trace ID for correlation
}
result is Promise<T>, not T. You need to await it to get the resolved value.

Creating child spans

Use ctx.span() inside a callback to create child spans under the current parent:
import { span } from "@agentmark-ai/sdk";

const { result, traceId } = await span(
  { name: 'multi-step-workflow' },
  async (ctx) => {
    await ctx.span({ name: 'validate-input' }, async (spanCtx) => {
      spanCtx.setAttribute('input.length', 42);
    });

    const output = await ctx.span({ name: 'process-request' }, async (spanCtx) => {
      const prompt = await client.loadTextPrompt('process.prompt.mdx');
      const input = await prompt.format({
        props: { query: 'process this' },
        telemetry: { isEnabled: true }
      });
      return await generateText(input);
    });

    await ctx.span({ name: 'format-response' }, async (spanCtx) => {
      spanCtx.addEvent('formatting-complete');
    });

    return output;
  }
);
ctx.span() accepts { name: string; metadata?: Record<string, string> }. Use observe() (below) if you need to set a SpanKind on a span.

Wrapping functions with observe()

observe() wraps an async function with automatic input/output capture AND lets you set a SpanKind. Unlike span() / ctx.span() which create inline spans, observe() produces a reusable function so every call is automatically traced.
import { observe, SpanKind } from "@agentmark-ai/sdk";

const searchWeb = observe(
  async (query: string) => {
    const response = await fetch(`https://api.search.com?q=${query}`);
    return response.json();
  },
  { name: "search-web", kind: SpanKind.TOOL }
);

// Every call is now automatically traced
const results = await searchWeb("AgentMark tracing");

observe() options

OptionTypeDescription
namestringDisplay name for the span (defaults to function name)
kindSpanKindType of operation (defaults to SpanKind.FUNCTION)
captureInput / capture_inputbooleanRecord function arguments (default: true)
captureOutput / capture_outputbooleanRecord return value (default: true)
processInputs / process_inputsfunctionTransform arguments before recording (useful for redacting sensitive data)
processOutputs / process_outputsfunctionTransform return value before recording
Observed functions automatically attach to the active trace context — they nest correctly inside span() / span_context() without extra wiring.

SpanKind values

KindDescription
SpanKind.FUNCTIONGeneric computation step (default)
SpanKind.LLMA call to a language model
SpanKind.TOOLAn external tool or API call
SpanKind.AGENTAn orchestration loop
SpanKind.RETRIEVALA vector database query or document search
SpanKind.EMBEDDINGA call to an embedding model
SpanKind.GUARDRAILA content safety or validation check

Using SpanKind in a pipeline

To set SpanKind on individual steps of a pipeline, wrap each step with observe() and call the wrapped functions inside span():
import { span, observe, SpanKind } from "@agentmark-ai/sdk";

const searchKB = observe(
  async (query: string) => vectorDb.query({ query, topK: 5 }),
  { name: 'search-knowledge-base', kind: SpanKind.RETRIEVAL }
);

const guardrail = observe(
  async (question: string) => moderationService.check(question),
  { name: 'check-content-policy', kind: SpanKind.GUARDRAIL }
);

const generateAnswer = observe(
  async (question: string, context: unknown) => {
    const prompt = await client.loadTextPrompt('answer.prompt.mdx');
    const input = await prompt.format({
      props: { question, context },
      telemetry: { isEnabled: true }
    });
    return generateText(input);
  },
  { name: 'generate-answer', kind: SpanKind.LLM }
);

const { result } = await span(
  { name: 'rag-pipeline' },
  async () => {
    const docs = await searchKB(userQuestion);
    await guardrail(userQuestion);
    return generateAnswer(userQuestion, docs);
  }
);

Scoring traces

Use sdk.score() to attach quality scores to traces or spans:
const { result, traceId } = await span(
  { name: 'scored-workflow' },
  async (ctx) => {
    return output;
  }
);

await sdk.score({
  resourceId: traceId,
  name: 'correctness',
  score: 0.95,
  label: 'correct',
  reason: 'Output matches expected result'
});

Best practices

  • Use meaningful function IDs"customer-support-greeting", not "func1"
  • Add relevant metadata — userId, environment, query parameters
  • Always enable telemetry in production — monitor performance and set up alerts
  • Shutdown tracer for short scripts — call tracer.shutdown() before the process exits

Next steps

Sessions

Group related traces together

Metadata

Add custom context to traces

Tags

Categorize traces with labels

PII masking

Redact sensitive data from traces

Have Questions?

We’re here to help! Choose the best way to reach us: