Add observability to an agent framework
Drop-in handlers for LangChain, OpenAI Agents, Anthropic, CrewAI, Deep Agents, LangGraph, LlamaIndex, Mastra, Vercel AI SDK, Google ADK and Semantic Kernel, plus what each one actually emits.
You already use a framework. You want every chain step, tool call and model interaction on a trace without wrapping each one by hand. Each integration is a handler, hook or middleware the framework already knows how to call.
Install
pip install "axonpush[langchain]" # LangChain / LangGraph
pip install "axonpush[openai-agents]" # OpenAI Agents SDK
pip install "axonpush[anthropic]" # Anthropic
pip install "axonpush[crewai]" # CrewAI
pip install "axonpush[deepagents]" # LangChain Deep Agents
pip install "axonpush[otel]" # OpenTelemetry exporter
pip install "axonpush[all]" # all of the abovePython ships one extra per framework. TypeScript ships them all in
@axonpush/sdk, imported from @axonpush/sdk/integrations/<name>, with the
framework itself as a peer dependency.
Python
LangChain and LangGraph
from axonpush import AxonPush
from axonpush.integrations.langchain import AxonPushCallbackHandler
client = AxonPush()
handler = AxonPushCallbackHandler(client, "ch_...", agent_id="my-agent")
chain.invoke({"input": "research AI frameworks"}, config={"callbacks": [handler]})AsyncAxonPushCallbackHandler is the AsyncAxonPush sibling.
OpenAI Agents SDK
from axonpush import AsyncAxonPush
from axonpush.integrations.openai_agents import AxonPushRunHooks
client = AsyncAxonPush()
hooks = AxonPushRunHooks(client, "ch_...")
result = await Runner.run(agent, input="research AI frameworks", hooks=hooks)Anthropic
from axonpush import AxonPush
from axonpush.integrations.anthropic import AxonPushAnthropicTracer
client = AxonPush()
tracer = AxonPushAnthropicTracer(client, "ch_...")
response = tracer.create_message(
anthropic_client,
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Research AI frameworks"}],
)CrewAI
from axonpush import AxonPush
from axonpush.integrations.crewai import AxonPushCrewCallbacks
client = AxonPush()
callbacks = AxonPushCrewCallbacks(client, "ch_...")
callbacks.on_crew_start()
result = Crew(
agents=[researcher, writer],
tasks=[research_task, write_task],
step_callback=callbacks.on_step,
task_callback=callbacks.on_task_complete,
).kickoff()
callbacks.on_crew_end(result)Deep Agents
from deepagents import create_deep_agent
from axonpush import AxonPush
from axonpush.integrations.deepagents import AxonPushDeepAgentHandler
client = AxonPush()
handler = AxonPushDeepAgentHandler(client, "ch_...", agent_id="deep-agent")
agent = create_deep_agent(tools=[], system_prompt="You are a helpful assistant.")
agent.invoke(
{"messages": [{"role": "user", "content": "Research AI frameworks"}]},
config={"callbacks": [handler]},
)AsyncAxonPushDeepAgentHandler is the async sibling.
TypeScript
Every integration takes the same config object: client, channelId, and
optionally agentId, traceId, mode, queueSize, overflowPolicy,
shutdownTimeoutMs, concurrency.
import { AxonPush } from "@axonpush/sdk";
import { AxonPushCallbackHandler } from "@axonpush/sdk/integrations/langchain";
import { AxonPushRunHooks } from "@axonpush/sdk/integrations/openai-agents";
import { axonPushMiddleware } from "@axonpush/sdk/integrations/vercel-ai";
const client = new AxonPush();
// LangChain
const handler = new AxonPushCallbackHandler({ client, channelId: "ch_...", agentId: "my-agent" });
await chain.invoke({ input: "…" }, { callbacks: [handler] });
// OpenAI Agents
const hooks = new AxonPushRunHooks({ client, channelId: "ch_..." });
// Vercel AI SDK - a LanguageModelMiddleware
const model = wrapLanguageModel({
model: openai("gpt-4.1"),
middleware: axonPushMiddleware({ client, channelId: "ch_..." }),
});Available under @axonpush/sdk/integrations/:
| Import path | Export |
|---|---|
langchain | AxonPushCallbackHandler |
langgraph | AxonPushLangGraphHandler |
openai-agents | AxonPushRunHooks |
anthropic | AxonPushAnthropicTracer |
llamaindex | AxonPushLlamaIndexHandler |
mastra | AxonPushMastraExporter, AxonPushMastraHooks |
vercel-ai | axonPushMiddleware |
google-adk | axonPushADKCallbacks |
otel | AxonPushSpanExporter |
sentry | installSentry, buildDsn |
pino | createAxonPushPinoStream |
winston | createAxonPushWinstonTransport |
console | setupConsoleCapture |
.NET
There is no callback-handler equivalent; the .NET SDK covers Semantic Kernel and general OpenTelemetry:
var builder = Kernel.CreateBuilder();
builder.AddAxonPushTelemetry(
client => { client.ApiKey = "ak_..."; client.TenantId = "org_..."; },
exporter => { exporter.ChannelId = "ch_..."; });See the .NET SDK reference. Note the wizard does not detect or wire .NET projects, install and configure these by hand.
What each integration emits
The identifier is what you filter and search on; the eventType is what
dashboards, webhooks and alert rules key off.
| Framework | Identifiers | Event types |
|---|---|---|
| LangChain | chain.start, chain.end, chain.error, llm.start, llm.end, llm.token, tool.<name>.start, tool.end, tool.error | agent.start, agent.end, agent.error, agent.llm.token, agent.tool_call.start, agent.tool_call.end |
| OpenAI Agents | agent.run.start, agent.run.end, agent.handoff, tool.<name>.start, tool.<name>.end | agent.start, agent.end, agent.handoff, agent.tool_call.start, agent.tool_call.end |
| Anthropic | conversation.turn, agent.response, agent.usage, tool.<name>.start, tool.result | agent.start, agent.message, agent.tool_call.start, agent.tool_call.end |
| CrewAI | crew.start, crew.end, agent.step, task.complete, tool.<name>.start, tool.<name>.end | agent.start, agent.end, agent.message, agent.tool_call.start, agent.tool_call.end |
| Deep Agents | everything LangChain emits, plus planning.update, planning.complete, subagent.spawn, subagent.complete, sandbox.execute, sandbox.execute.complete | as LangChain, plus agent.handoff |
Log forwarders, logging, loguru, structlog, pino, winston,
console, emit app.log and are covered in the SDK references, not here.
Publishing off the hot path
Every Python integration publishes through a background publisher by
default: events go onto an in-memory queue and a worker thread drains it, so a
slow network never blocks a chain step. Pass mode="sync" to publish inline,
useful in a test, wrong in production, or mode="rq" to hand off to an RQ
queue. TypeScript takes the same mode on its config object and additionally
offers a BullMQ publisher.
handler = AxonPushCallbackHandler(
client,
"ch_...",
agent_id="my-agent",
mode="background", # "background" (default) | "sync" | "rq"
# CrewAI accepts "background" and "sync" only
queue_size=1000,
shutdown_timeout=5.0,
)A short-lived process, a Lambda handler, a CLI, should either use mode="sync"
or flush before exit, or the queue dies with the process and the tail of the run
never arrives. The TypeScript publisher exposes flushAfterInvocation and
detects serverless runtimes for exactly this.
Integrations always suppress publish errors, whatever the client’s
fail_open setting. An observability failure cannot break the pipeline it is
watching. That also means a silently misconfigured channel produces no events
and no complaint, verify once, at wiring time, that events are landing.
Sharing a trace across integrations
Pass the same trace_id and two services’ events land in one trace:
handler = AxonPushCallbackHandler(client_a, "ch_a", trace_id=shared)
hooks = AxonPushRunHooks(client_b, "ch_b", trace_id=shared)If you leave trace_id out, each integration adopts the ambient trace context,
which, in one process, is already shared. See
Trace a multi-step agent run.
Next
- Let a coding agent wire it up, the skills do the above for you
- Trace a multi-step agent run, correlating what these emit
- Handle errors and rate limits, the
modeandfail_openbehaviour in full
Command-line tools
The two axonpush CLIs, the wizard launcher that installs the integration skills and opens your coding agent, and the self-host installer that provisions the whole stack into your AWS account.
Trace a multi-step agent run end to end
Correlate every event in one run under a single trace ID, propagate it across services and into OpenTelemetry, and read the result back as a waterfall.