Skip to main content
Lemma reads a specific trace shape to power input/output display, model visibility, timing, tool visibility, threads, and automated issue detection. This page is the canonical contract; every other page builds on it.
One agent execution = one trace. LLM calls, tool calls, retrieval, and app logic are child records inside that trace, not separate traces.

The product contract

ConceptWhat it isLemma primitive
TraceOne end-to-end agent execution, from user input to final responseRoot trace
SpanA unit of work inside the trace (retrieval, ranking, app logic)Child span
GenerationA single LLM call (prompt, completion, model, timing)Child span typed as a generation
Tool callA single tool invocation (name, arguments, result)Child span typed as a tool
A useful trace has:
  • A root trace with the user input and the final output (or error).
  • A stable agent name so traces are groupable by workflow.
  • Generation records carrying model, input, and output.
  • Tool records carrying arguments and results.
  • A thread id when the execution is part of a multi-turn conversation.

How the SDK satisfies it

import { Lemma } from "@uselemma/tracing";

const lemma = new Lemma();

await lemma.trace(
  {
    name: "support-agent",
    input: userMessage,
    threadId,
    userId,
  },
  async (trace) => {
    const docs = await searchDocs(userMessage);
    trace.recordTool({
      name: "search_docs",
      input: { query: userMessage },
      output: docs,
    });

    const response = await callModel(userMessage, docs);
    trace.recordGeneration({
      name: "draft-reply",
      input: response.messages,
      output: response.text,
      model: "gpt-4o",
    });

    return response.text;
  },
);

SDK field mapping

Contract fieldTypeScript SDK APIPython SDK APIAttribute keys emitted
Trace inputlemma.trace({ input })lemma.trace(..., input=...)input.value, ai.agent.input
Trace outputCallback return value or trace.output(output)Callback return value or trace.output(output)output.value, ai.agent.output, ai.response.text for string output
Trace durationMeasured automatically, lemma.trace({ durationMs }), or trace.end({ durationMs })Measured automatically or lemma.trace(..., duration_ms=...)Trace duration_ms, root span duration
Agent namelemma.trace({ name })lemma.trace("name", ...)gen_ai.agent.name, ai.agent.name
Thread idthreadIdthread_idlemma.thread_id
User iduserIduser_iduser.id, enduser.id
LLM modeltrace.recordGeneration({ model })trace.record_generation(model=...)gen_ai.request.model, ai.model.id
Prompt / completiontrace.recordGeneration({ input, output })trace.record_generation(input=..., output=...)input.value, output.value
Child durationdurationMs, or inferred from the parent when omittedduration_ms, or inferred from the parent when omittedSpan duration_ms
Contract propsNative child props such as llmInputMessages, toolParameters, embeddingModelName, and rerankerOutputDocuments; raw attributes for escape-hatch keysSnake_case props such as llm_input_messages, tool_parameters, embedding_model_name, and reranker_output_documents; raw attributes for escape-hatch keysLemma span attributes
Generation spantrace.recordGeneration(...)trace.record_generation(...)Generation kind marker
Tool nametrace.recordTool({ name })trace.record_tool(name=...)Span name, tool.name
Tool args / resulttrace.recordTool({ input, output })trace.record_tool(input=..., output=...)input.value, output.value, ai.toolCall.args, ai.toolCall.result
Errorthrown error, trace.fail(error), or child errorraised exception, trace.fail(error), or child errorError status and error.message

Native contract props

The SDK exposes common Lemma contract fields as native props. Use these instead of hand-building flattened attribute names. In Python, use the snake_case form of the same prop, such as llm_input_messages, tool_parameters, and embedding_model_name.
SDK propUse onAttribute keys emitted
inputMimeTypeSpan, generation, toolinput.mime_type
outputMimeTypeSpan, generation, tooloutput.mime_type
llmModelNameGenerationllm.model_name
llmProviderGenerationllm.provider
llmSystemGenerationllm.system
llmInvocationParametersGenerationllm.invocation_parameters
llmInputMessagesGenerationllm.input_messages.{index}.message.*
llmOutputMessagesGenerationllm.output_messages.{index}.message.*
llmToolsGenerationllm.tools
llmPromptTemplateGenerationllm.prompt_template.template
llmPromptTemplateVariablesGenerationllm.prompt_template.variables
llmPromptTemplateVersionGenerationllm.prompt_template.version
toolDescriptionTooltool.description
toolParametersTooltool.parameters
embeddingModelNameSpanembedding.model_name
embeddingInvocationParametersSpanembedding.invocation_parameters
embeddingEmbeddingsSpanembedding.embeddings
rerankerModelNameSpanreranker.model_name
rerankerInputDocumentsSpanreranker.input_documents.{index}.document.*
rerankerOutputDocumentsSpanreranker.output_documents.{index}.document.*
model also populates llm.model_name for generation records. Object and array values are serialized where Lemma expects string-valued attributes. For fields without a native prop, pass raw attributes.

Child duration inference

When a child span, generation, or tool does not specify durationMs, Lemma infers it from the parent duration. Explicit child durations claim time first, then siblings without explicit durations split the remaining parent time equally. For example, if a trace took 1000ms, child c specified 500ms, and siblings a and b omitted duration, Lemma records a = 250ms, b = 250ms, and c = 500ms. The same rule applies recursively inside nested spans. If explicit siblings already exceed the parent duration, omitted siblings receive 0ms.

Required vs optional

FieldRequired?Without it
Single root trace per executionRequiredEach call becomes its own trace; no agent view
Root inputRequiredTraces show timing only
Root output or errorRequiredYou cannot tell success from failure
Agent nameRecommendedTraces are hard to group and filter
Generation model + contentRecommendedModel calls are hard to inspect or group
Tool name + args + resultRecommendedTool calls are invisible or opaque
Thread idOptionalMulti-turn conversations are not grouped
User / environmentOptionalNo per-user or per-environment slicing