Skip to content
Monitoring
Skill

/maple-agent-tracing-vercel-ai-sdk

Trace Vercel AI SDK agents with Maple: register the AI SDK's OpenTelemetry integration, export to Maple, and pass a conversation id so each chat is one Agent Session with transcript, tool calls, sub-agents and tokens. Covers generateText, streamText, ToolLoopAgent, Node.js and

BOOST
From plugin
maple
1.8k37 skills
Install
$ npx -y skills add mapletechlabs/maple --skill maple-agent-tracing-vercel-ai-sdk --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/maple-agent-tracing-vercel-ai-sdk

Context preview

The summary Claude sees to decide when to auto-load this skill.

Trace Vercel AI SDK agents with Maple: register the AI SDK's OpenTelemetry integration, export to Maple, and pass a conversation id so each chat is one Agent Session with transcript, tool calls, sub-agents and tokens. Covers generateText, streamText, ToolLoopAgent, Node.js and

SKILL.md

maple-agent-tracing-vercel-ai-sdk.SKILL.md
name: maple-agent-tracing-vercel-ai-sdk
description: "Trace Vercel AI SDK agents with Maple: register the AI SDK's OpenTelemetry integration, export to Maple, and pass a conversation id so each chat is one Agent Session with transcript, tool calls, sub-agents and tokens. Covers generateText, streamText, ToolLoopAgent, Node.js and Next.js. Triggers on 'trace my vercel ai sdk agent', 'add Maple to vercel ai sdk', 'agent sessions for vercel ai sdk', 'OpenTelemetry for vercel ai sdk', 'trace my ai sdk app'."

Maple agent tracing: Vercel AI SDK

Goal

One conversation = one Maple Agent Session, one turn per `generate()`/`stream()` call, with the transcript, every model call (model, tokens, TTFT), every tool call (name, args, result, failures), and a lane per sub-agent.

Known gaps (tell the user, don't try to fix): cost shows as "unpriced" (AI SDK emits no cost; Maple never prices tokens); on AI SDK 5/6 the final assistant reply is missing from transcripts. If model calls go through OpenRouter, its Broadcast traces carry per-call cost and Maple matches them to the AI SDK `chat` spans by response id (see the OpenRouter guide).

Step 0: Detect

  • `ai` version in `package.json` / lockfile:
  • `>= 7`: this skill. Upgrade to `^7.0.106` or newer if older (earlier 7.x leave spans open when a stream errors mid-read). Node.js >= 22 required.
  • `5.x` / `6.x`: ask the user whether to upgrade to 7 (recommended; `npx @ai-sdk/codemod v7`). The codemod only renames `experimental_telemetry` to `telemetry`; you still install `@ai-sdk/otel`, call `registerTelemetry()`, and move the id from `metadata` (removed in 7) to `runtimeContext`, then drop any `ConversationIdProcessor`. If not, go to "AI SDK 5/6" at the end.
  • Mastra (`@mastra/core`) or another framework built on `ai`: stop, use that framework's skill instead.
  • Existing OpenTelemetry: search for `NodeSDK`, `NodeTracerProvider`, `registerOTel`, `@vercel/otel`, `Sentry.init`, `@langfuse/otel`, `LangfuseSpanProcessor`, `braintrust`, `registerTelemetry(`, `experimental_telemetry`, `telemetry:`.
  • An SDK/provider already exists: reuse it. Add one Maple exporting span processor to it. Never start a second SDK.
  • `registerTelemetry(...)` already exists: extend that call's `OpenTelemetry` options; never call it twice (it appends, so every span is emitted twice).
  • `LegacyOpenTelemetry` registered: replace it with `OpenTelemetry` unless the user says another backend depends on the legacy format. Never register both.
  • Next.js app (`next` dependency, `instrumentation.ts`): use Step 2b.
  • Find every AI SDK call site: `generateText(`, `streamText(`, `new ToolLoopAgent(`, `createAgentUIStreamResponse(`, `pipeAgentUIStreamToResponse(`, `createAgentUIStream(`, `agent.generate(`, `agent.stream(`. Find each one's conversation id (chat id, thread id, `useChat` request body `id`).

Step 1: Key and region

  • US endpoint `https://ingest.maple.dev`, EU endpoint `https://ingest.eu.maple.dev`. Header `Authorization=Bearer <key>`.
  • Key in the user's prompt: use it. No key: use the literal `MAPLE_TEST` (ingest accepts and discards it) and tell the user to replace it with their key from Settings → Ingestion.
  • Private `maple_sk_` keys never go in browser code. Ingest keys are write-only.
  • Follow the repo's existing secret/env convention (e.g. `MAPLE_INGEST_KEY` or `OTEL_EXPORTER_OTLP_*` in `.env`). If there is none, inlining the ingest key is acceptable.
  • The app loads `.env` (`dotenv`, `--env-file`): load it at the top of `instrumentation.ts` (`import "dotenv/config"` as its first line) or run with `--env-file`. `NodeSDK()` reads the `OTEL_*` vars when it is constructed; otherwise the exporter silently targets `localhost:4318` with no key.
  • Never let an unset variable become `Bearer undefined` (opaque 401). When the key variable is missing, log one warning (`MAPLE_INGEST_KEY is not set; Maple telemetry export is disabled`) and leave the Maple exporter out so the app runs normally; never throw over the key. Or inline the key when the repo has no env convention.
  • A 401 `ingest_unauthorized` / "Invalid ingest key" with a key you trust usually means the key belongs to the other region (keys are region-bound): try the other endpoint.

Step 2a: Install and init (Node.js)

npm install ai@^7.0.106 @ai-sdk/otel @opentelemetry/sdk-node

Use the repo's package manager (`@opentelemetry/api` arrives as a peer of `sdk-node`; add it explicitly only if the package manager doesn't install peers). Works on Node.js 22+ and Bun. Env (or the repo's equivalent):

OTEL_SERVICE_NAME=support-agent
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.maple.dev
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <key>"

`NodeSDK()` with no span processors builds a batched OTLP http/protobuf exporter from these variables. Create `instrumentation.ts`:

import { OpenTelemetry } from "@ai-sdk/otel"
import { NodeSDK } from "@opentelemetry/sdk-node"
import { registerTelemetry } from "ai"

export const sdk = new NodeSDK()
sdk.start()

registerTelemetry(
	new OpenTelemetry({
		usage: true,
		runtimeContext: true,
	}),
)

Use the explicit span processor variant instead when either applies:

  • Serverless handler (Lambda, Cloud Run jobs, queue consumers, cron, Vercel Workflow steps): needs `spanProcessor.forceFlush()` per invocation; `NodeSDK` only has `shutdown()`.
  • The repo already starts an OpenTelemetry SDK/provider: add the processor to it, don't create a second `NodeSDK`.
  • Inlining the key instead of env: pass `{ url: "https://ingest.maple.dev/v1/traces", headers: { authorization: "Bearer <key>" } }` to `OTLPTraceExporter`.
npm install @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto"
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"

export const spanProce
Read more
Ships withmaple

OpenTelemetry observability platform

Get the whole plugin

Other skills on maple.