maple-agent-tracing-ag…
Trace Agno agents with Maple: installs the OpenInference Agno instrumentor with an OTLP…
Trace OpenRouter calls with Maple: route OpenRouter Broadcast (OTLP) to Maple and edit the app's OpenRouter requests to send session_id and trace ids, so each conversation is one Maple Agent Session with model calls, tokens and real cost. Triggers on 'trace my openrouter calls',
$ npx -y skills add mapletechlabs/maple --skill maple-agent-tracing-openrouter --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/maple-agent-tracing-openrouterContext preview
The summary Claude sees to decide when to auto-load this skill.
Trace OpenRouter calls with Maple: route OpenRouter Broadcast (OTLP) to Maple and edit the app's OpenRouter requests to send session_id and trace ids, so each conversation is one Maple Agent Session with model calls, tokens and real cost. Triggers on 'trace my openrouter calls',
name: maple-agent-tracing-openrouter description: "Trace OpenRouter calls with Maple: route OpenRouter Broadcast (OTLP) to Maple and edit the app's OpenRouter requests to send session_id and trace ids, so each conversation is one Maple Agent Session with model calls, tokens and real cost. Triggers on 'trace my openrouter calls', 'add Maple to openrouter', 'agent sessions for openrouter', 'OpenTelemetry for openrouter', 'openrouter broadcast to maple'."
Goal: every conversation = one Maple Agent Session with each OpenRouter model call, its tokens, cost (`gen_ai.usage.total_cost`, OpenRouter's real charge) and prompt/completion. If the app already exports its own traces to Maple, the Broadcast spans nest inside them and each call is counted once.
Mechanism: OpenRouter Broadcast, configured in the OpenRouter dashboard, exports one OTLP/HTTP JSON trace per request (scope and `service.name` = `openrouter`, root span `LLM Generation`, children `provider attempt N: <provider>`). Maple reads **`session.id`** as the session key. OpenRouter sets `session.id` from the request's `session_id` body field or `x-session-id` header, and uses `trace.trace_id` / `trace.parent_span_id` from the body verbatim as the OTLP trace id / parent span id.
You cannot change the OpenRouter dashboard. Your job: (1) edit the app's OpenRouter calls, (2) hand the user the exact destination settings.
What Broadcast cannot give (tell the user, don't try to fix it here): tool spans, tool failures, agent names / sub-agent lanes. Those need the app's framework instrumentation (router skill `maple-agent-tracing`).
1. Find every OpenRouter call site: `openrouter.ai` base URLs (`https://openrouter.ai/api/v1`, `https://eu.openrouter.ai/api/v1`), `OPENROUTER_API_KEY`, `@openrouter/ai-sdk-provider`, `@openrouter/sdk`, the `openrouter` PyPI package, `openai` clients with an OpenRouter `baseURL` / `base_url`, LiteLLM `openrouter/` models, framework model classes pointed at OpenRouter. 2. Find where the conversation id lives per request: chat thread id, conversation id, session id, agent run id. It must be per conversation, never a process constant or a per-client default. 3. Existing OTel exporting to Maple? Search for `TracerProvider`, `NodeSDK`, `registerOTel`, `registerTelemetry`, `OTEL_EXPORTER_OTLP_ENDPOINT`, `ingest.maple.dev`, `logfire.configure`, OpenInference / OpenLLMetry instrumentors.
4. Which endpoint region the app calls (`openrouter.ai` vs `eu.openrouter.ai`), for the destination's data regions.
Same id for every request of one conversation, new id per conversation, max 256 characters. If the app also has framework instrumentation, use the SAME value as the framework's conversation/session id (a trace with two different ids is assigned to the lexically larger one, silently).
`openai` npm (>= 7; field is untyped, sent as-is):
const completion = await client.chat.completions.create({
model,
messages,
// @ts-expect-error OpenRouter-only field
session_id: conversationId,
})Or per-request header, no type workaround:
await client.chat.completions.create({ model, messages }, { headers: { "x-session-id": conversationId } })`openai` PyPI (>= 3): `extra_body={"session_id": conversation_id}` on `chat.completions.create(...)` (and on `responses.create(...)` if used).
Vercel AI SDK + `@openrouter/ai-sdk-provider` (>= 3.1): `providerOptions: { openrouter: { session_id: conversationId } }` on `generateText` / `streamText` / agent calls. Everything under `providerOptions.openrouter` is merged into the body.
`@openrouter/sdk`: `openRouter.chat.send({ model, messages, sessionId: conversationId })`. `openrouter` PyPI: `session_id=conversation_id`.
Other clients: find the framework's extra-body or per-request-headers option and set `session_id` / `x-session-id`. Check the outgoing request (log the body once, or a test that captures `fetch`) to confirm the field is actually sent; some wrappers drop unknown fields.
Optional: `user` (<= 128 chars) is forwarded as `user.id`. Maple does not use it for sessions. Never put emails/names in `user`, `session_id` or `trace` metadata: Privacy Mode does not strip them.
Without this, every model call is recorded twice (app span + Broadcast trace) and Broadcast-only turns split one per model call. Put the active span's W3C ids in `trace.trace_id` (32 hex) and `trace.parent_span_id` (16 hex).
TypeScript: wrap `fetch` and pass it to the client (`new OpenAI({ baseURL, apiKey, fetch: openRouterFetch })` or `createOpenRouter({ apiKey, fetch: openRouterFetch })`). Reads the span active when the SDK sends the request, which is the framework's model-call span if it has one:
import { trace } from "@opentelemetry/api"
// Nests each OpenRouter Broadcast trace under the span that made the request.
export const openRouterFetch: typeof fetch = (input, init) => {
const span = trace.getActiveSpan()?.spaRepo: mapletechlabs/maple
Trace Agno agents with Maple: installs the OpenInference Agno instrumentor with an OTLP…
Trace Claude Agent SDK agents (TypeScript and Python) and Claude Code CLI sessions with…
Trace Cloudflare Agents SDK agents (AIChatAgent, Agent on Durable Objects, npm `agents` /…
Trace CrewAI crews and flows with Maple: OpenInference CrewAI instrumentor plus the model-SDK…
Trace DSPy programs and ReAct agents with Maple: OpenInference DSPy instrumentor with GenAI…
Trace Genkit (TypeScript/Node.js) agents with Maple: export Genkit's OpenTelemetry spans to…