Anthropic
AxonPushAnthropicTracer wraps messages.create and messages.stream, recording tool use, text blocks, stop reason, and token usage including cache hits.
AxonPushAnthropicTracer wraps calls to the Anthropic Messages API. You call
the tracer instead of the client, it forwards the call, and it records the turn
, the model’s response blocks, the stop reason, and full token usage including
cache reads and writes.
Tested against @anthropic-ai/sdk@^0.30.
Install
npm install @axonpush/sdk @anthropic-ai/sdk
Non-streaming
import Anthropic from "@anthropic-ai/sdk";
import { AxonPush, AxonPushAnthropicTracer } from "@axonpush/sdk";
const client = new AxonPush();
const tracer = new AxonPushAnthropicTracer({
client,
channelId: process.env.AXONPUSH_CHANNEL_ID!,
});
const anthropic = new Anthropic();
const response = await tracer.createMessage(anthropic, {
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain quantum computing." }],
});
createMessage takes the Anthropic client as its first argument and the
ordinary messages.create params as its second, and returns the unmodified
response. agentId defaults to "claude".
Streaming
streamMessage is an async generator: it yields every raw stream event
through to you, recording tokens as they pass.
for await (const event of tracer.streamMessage(anthropic, {
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain quantum computing." }],
stream: true,
})) {
if (event.type === "content_block_delta") process.stdout.write(event.delta.text ?? "");
}
It prefers anthropic.messages.stream(params) when the client exposes it and
falls back to messages.create({ ...params, stream: true }). Usage and stop
reason are captured from the terminal message_delta / message_stop events,
so the closing conversation.turn.end still carries token counts.
Tool results
The tracer sees the model’s tool_use blocks on the way out, but it cannot see
what your code did with them. Report the result back yourself:
tracer.sendToolResult(toolUseId, result);
What gets emitted
| Identifier | axonpush eventType | Payload |
|---|---|---|
conversation.turn | agent.start | model, message_count, streaming when applicable |
agent.response | agent.message | text_length, one per text block |
tool.{name}.start | agent.tool_call.start | tool_name, tool_use_id, truncated input |
tool.result | agent.tool_call.end | tool_use_id, result_preview (first 500 chars) |
llm.token | agent.llm.token | token, streaming only |
conversation.turn.end | agent.end | stop_reason and the usage fields below |
Usage on conversation.turn.end: input_tokens, output_tokens,
cache_creation_input_tokens, cache_read_input_tokens. Fields the API did
not return are recorded as null rather than omitted, so a prompt-caching
regression is visible as a change in value rather than a missing key.
Assistant text is recorded as a length, not content. Tool inputs are
truncated to 500 characters and then pass through the client’s redactor, which
under the default metadata_only capture mode replaces content-bearing keys
outright. Every event carries metadata.framework: "anthropic".