foglamp() collector needs the telemetry API introduced in AI SDK v7. On
v4, v5, or v6, use the foglamp/wrap entry point instead. It wraps the AI SDK
functions and produces the same traces to the same endpoint.
wrap() supports AI SDK v4 and later. On v7, prefer the native
foglamp() collector. The package declares
ai@^4 || ^5 || ^6 || ^7.0.0-beta.1 as a peer dependency.What it captures
Each wrapped call becomes one trace, with the same shape as the v7 path:generateText/streamText: a root span, onellmspan per step, and onetoolspan per tool call.generateObject/streamObject: a root span plus onellmspan.- Agent classes:
wrap()also returns wrapped, drop-in versions ofToolLoopAgentandExperimental_Agent.agent.generate()andagent.stream()are traced likegenerateTextandstreamText. If the agent has anidand noagentNamewas set, theidis used as theagentName. - Exact tool timing:
wrap()times each tool’sexecutedirectly, so tool spans have a real measured duration. - Streaming stats: for
streamText, Foglamp watches the stream through the call’sonChunkcallback to record time to first token and the token curve behind tokens/sec and replay. It never consumes or changes your stream. - Provider signals: every
llmspan carries what the provider reports, such as grounding sources, the OpenAI-stylesystem_fingerprint, safety ratings, and rate-limit headroom. One difference from v7:wrapmeasures exact tool time but cannot separate out the model-only window, so it omitsmodelCallMsrather than guess.
Per-call context
Contexts stack in layers, and later layers win per field:wrap(ai, { context })
sets the default, fog.run(context, fn) sets context for a block of code,
fog.with(context) binds on top of both, and a call-time foglamp option wins
over all three. metadata maps merge across layers, with inner keys winning.
fog.run() sets context for everything inside a callback. Use it for
things scoped to one run: workflow run ids, session ids, request metadata. Every
wrapped call inside the callback picks up the context, no matter how deeply
nested, with no parameters to pass around. Module-level singleton agents stay
singletons.
run() calls merge, inner over outer. Works on Node, Bun, Deno, and
Vercel or Cloudflare edge runtimes (anywhere node:async_hooks exists). The v7
collector has the same method: fog.run() layers under fog.integration().
On the v7 collector, a model call made inside a tool’s
execute inherits the
parent call’s workflow and session context automatically (see the
SDK overview). The wrap path has
no such hook, so on v4 to v6 use fog.run() to share context with a tool
that calls back into the model.fog.with() keeps your types. It returns the wrapped functions and agent
classes typed exactly like the AI SDK’s originals, so generics, Output.object
result types, and tool typings all survive:
foglamp option on any wrapped call; it is removed before
the arguments reach the AI SDK. Calls that use it lose the AI SDK’s generic
result types, so prefer with() when you need the typed result:
fog.integration(context): traceName, agentName,
workflowName + workflowRunId, sessionId, and metadata.
Agent classes
When the module exportsToolLoopAgent (v6/v7) or Experimental_Agent (v5),
wrap() returns wrapped versions with the same constructor and methods.
Instrument them in place; there is no need to rewrite agent code to
generateText:
onStepFinish and onFinish callbacks still run; Foglamp composes with
them. One gap: agent streams expose no onChunk, so agent.stream() traces
have no time to first token or token-curve samples (plain streamText does).
Your callbacks are preserved
If you passonChunk, onStepFinish, onFinish, or onError to a wrapped
call, your callback always runs. Foglamp’s telemetry runs alongside it and
never throws into your app.
Flushing
wrap() returns flush() and shutdown() alongside the wrapped functions.
Use them exactly as on the collector (see
Runtimes and flushing). Serverless platforms are detected
automatically, and on Vercel the invocation is kept alive with waitUntil from
the runtime’s request context, with nothing to install. On other serverless
platforms pass waitUntil in the config (for example Cloudflare’s
ctx.waitUntil) or await fog.flush() before the handler returns.
Configuration
wrap(ai, options) accepts every configuration field the
collector does (apiKey, endpoint, recordInputs, recordOutputs,
maxPayloadChars, waitUntil, and so on), plus context for the default
context.
Limits compared to v7
- A client-side tool (one with no
executefunction, run by your app) can’t be timed directly, so its time is attributed at step boundaries rather than as an exact duration. Tools with anexecuteare timed precisely. wrap()instruments a module you pass in; there is no globalregisterTelemetryon v4 to v6.
.png?fit=max&auto=format&n=1sml0kwCw1BNtiz-&q=85&s=a7c846a133aa3480dc1e03a2da5fec2b)
.png?fit=max&auto=format&n=1sml0kwCw1BNtiz-&q=85&s=6534218552b79980770f11c40aafd6ec)