Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mortemlabs.com/llms.txt

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

Mortem wraps the Anthropic client structurally, patching messages.create at runtime without importing the @anthropic-ai/sdk package. The wrapper is compatible with any version of the Anthropic SDK and adds no extra dependency to your agent.

What gets captured

For each call to messages.create, Mortem records an llm_call event containing:
  • System prompt — the system field if present
  • Messages — the full message array including role and content
  • Completion — text extracted from all text content blocks in the response
  • Tool use — structured tool_use blocks with name, ID, and input arguments
  • Model — the model string from the request parameters
  • Token usageinput_tokens and output_tokens from the response
  • Stop reasonend_turn, max_tokens, tool_use, or any other stop_reason value
Both standard and streaming responses are captured. For streaming, Mortem accumulates content_block_delta text chunks and records usage from the message_delta event.

Prerequisites

Install the SDK and create an agent in the dashboard before continuing. You need MORTEM_API_KEY and MORTEM_AGENT_ID set in your environment.

Integration

1

Initialize the Mortem client

Create a Mortem instance at module scope, typically once at the start of your agent process.
import { Mortem } from "@mortemlabs/sdk"

const mortem = new Mortem({
  apiKey: process.env.MORTEM_API_KEY ?? "",
  agentId: process.env.MORTEM_AGENT_ID,
  verifyToken: process.env.MORTEM_VERIFY_TOKEN, // remove after first verified run
  environment: "devnet",
})
verifyToken is only needed during your first deployment. Once the dashboard shows the agent as verified, remove MORTEM_VERIFY_TOKEN from your environment and code.
2

Wrap the Anthropic client

Pass your Anthropic client instance to mortem.wrapAnthropic. The wrapper patches messages.create in place and returns the same client reference.
import Anthropic from "@anthropic-ai/sdk"

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
const tracedAnthropic = mortem.wrapAnthropic(anthropic)
You can wrap the client at the point of construction to ensure every call in the module is traced:
const anthropic = mortem.wrapAnthropic(
  new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
)
3

Start a session and run the agent

Create a session with mortem.startSession, then run your agent logic inside session.run. Any messages.create call made through the wrapped client inside the callback is automatically associated with this trace.
const session = await mortem.startSession({
  inputSummary: "Evaluate current market conditions and produce a trade recommendation",
  tags: ["anthropic", "devnet"],
})

try {
  const result = await session.run(async () => {
    return tracedAnthropic.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 1024,
      system: "You are a Solana trading bot. Analyze market data and recommend a trading action.",
      messages: [
        {
          role: "user",
          content: "SOL is at $145 and JUP is at $0.62. Volume is elevated on both pairs. Should I swap 1 SOL for JUP?",
        },
      ],
    })
  })

  const decision =
    result.content
      .filter((block) => block.type === "text")
      .map((block) => block.text)
      .join("") ?? ""

  await session.complete(decision)
} catch (error) {
  await session.fail(error)
} finally {
  await mortem.close()
}
Always call mortem.close() in a finally block. It flushes the trace buffer and ensures all events reach the ingest service before the process exits.

Complete example

import { Mortem } from "@mortemlabs/sdk"
import Anthropic from "@anthropic-ai/sdk"

const mortem = new Mortem({
  apiKey: process.env.MORTEM_API_KEY ?? "",
  agentId: process.env.MORTEM_AGENT_ID,
  verifyToken: process.env.MORTEM_VERIFY_TOKEN,
  environment: "devnet",
})

const anthropic = mortem.wrapAnthropic(
  new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
)

const session = await mortem.startSession({
  inputSummary: "Evaluate current market conditions and produce a trade recommendation",
  tags: ["anthropic", "devnet"],
})

try {
  const result = await session.run(async () => {
    return anthropic.messages.create({
      model: "claude-opus-4-5",
      max_tokens: 1024,
      system: "You are a Solana trading bot. Analyze market data and recommend a trading action.",
      messages: [
        {
          role: "user",
          content: "SOL is at $145 and JUP is at $0.62. Volume is elevated on both pairs. Should I swap 1 SOL for JUP?",
        },
      ],
    })
  })

  const decision =
    result.content
      .filter((block) => block.type === "text")
      .map((block) => block.text)
      .join("")

  await session.complete(decision)
} catch (error) {
  await session.fail(error)
} finally {
  await mortem.close()
}

Streaming

When you set stream: true, the wrapper detects the async-iterable response and taps it using a generator. It reads content_block_delta events for text accumulation and message_delta events for the final stop_reason and usage. The llm_call event is completed when the stream ends.
const stream = await anthropic.messages.create({
  model: "claude-opus-4-5",
  max_tokens: 1024,
  stream: true,
  messages: [{ role: "user", content: "Evaluate current market risk." }],
})

let text = ""
for await (const event of stream) {
  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    text += event.delta.text
  }
}

await session.complete(text)
No additional configuration is needed — the same wrapped client handles both streaming and non-streaming calls.

Tool use

When the response contains tool_use content blocks, Mortem extracts them and records each tool call under the output.toolCalls field of the llm_call event. Each entry includes the tool call ID, tool name, and the full input object.
To also trace the actual execution of your tool functions, wrap each call with session.beginEvent("tool_call", payload) and complete it when the tool returns. If you use the Vercel AI SDK wrapper, tool execution tracing is handled automatically.