> ## 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.

# Instrument Anthropic Messages API calls with Mortem

> Wrap your Anthropic client with Mortem to capture every Messages API call — prompts, completions, tool use blocks, token usage, and stop reason.

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 usage** — `input_tokens` and `output_tokens` from the response
* **Stop reason** — `end_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

<Steps>
  <Step title="Initialize the Mortem client">
    Create a `Mortem` instance at module scope, typically once at the start of your agent process.

    ```ts theme={null}
    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",
    })
    ```

    <Note>
      `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.
    </Note>
  </Step>

  <Step title="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.

    ```ts theme={null}
    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:

    ```ts theme={null}
    const anthropic = mortem.wrapAnthropic(
      new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
    )
    ```
  </Step>

  <Step title="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.

    ```ts theme={null}
    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()
    }
    ```

    <Warning>
      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.
    </Warning>
  </Step>
</Steps>

## Complete example

```ts theme={null}
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.

```ts theme={null}
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.

<Tip>
  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.
</Tip>
