Trace VoltAgent with Future AGI
Send VoltAgent's native agent, model, tool and memory spans to Future AGI with the maintained @traceai/voltagent processor.
Send VoltAgent’s native OpenTelemetry spans to Future AGI with FIVoltAgentSpanProcessor from @traceai/voltagent. The processor maps VoltAgent attributes to Future AGI fields without patching your agents or changing the spans sent to VoltOps and other processors.
Prerequisites
- Node.js 22 or later. This guide uses VoltAgent 2.11.0; the integration’s peer dependency is
@voltagent/core@^2.11.0. - Future AGI API and secret keys, and your own OpenAI API key for the example.
Install
npm install @traceai/voltagent@0.1.0 @traceai/fi-core@1.1.1 @voltagent/core@2.11.0
npm install ai@6.0.309 @ai-sdk/openai@3.0.130 zod@4.6.7
Configure credentials
export FI_API_KEY="YOUR_FUTURE_AGI_API_KEY"
export FI_SECRET_KEY="YOUR_FUTURE_AGI_SECRET_KEY"
export FI_PROJECT_NAME="my-voltagent-app"
export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
Content is captured by default. Set the privacy flags before creating the processor if you do not want to export prompts, answers or tool payloads.
Add tracing and run an agent
Save this as voltagent.mjs. The weather tool returns sample data so the example needs no weather-service account.
import { ProjectType, register } from "@traceai/fi-core";
import { FIVoltAgentSpanProcessor } from "@traceai/voltagent";
import { Agent, VoltAgent, VoltAgentObservability, createTool } from "@voltagent/core";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
const tracerProvider = register({
projectName: process.env.FI_PROJECT_NAME,
projectType: ProjectType.OBSERVE,
// VoltAgent must register its own provider globally.
setGlobalTracerProvider: false,
});
const observability = new VoltAgentObservability({
spanProcessors: [new FIVoltAgentSpanProcessor({ tracerProvider })],
});
const weather = createTool({
name: "get_weather",
description: "Get sample weather for a city",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => ({ city, tempC: 21, conditions: "sunny" }),
});
const agent = new Agent({
name: "weather-agent",
instructions: "Answer weather questions using the sample data from get_weather.",
model: openai.chat("gpt-4.1-nano"),
tools: [weather],
});
const app = new VoltAgent({ agents: { weatherAgent: agent }, observability });
try {
const result = await agent.generateText("What is the weather in Lisbon?", {
userId: "user-123",
conversationId: "conversation-456",
});
console.log(result.text);
} finally {
try {
await app.shutdown();
} finally {
// This script owns the Future AGI provider; close it after VoltAgent.
await tracerProvider.shutdown();
}
}
node voltagent.mjs
Keep setGlobalTracerProvider: false: if the Future AGI provider is global instead, VoltAgent spans bypass the mapping and privacy rules in spanProcessors. Add this processor alongside any existing processors, not in place of them. VoltAgent’s scope filter applies to every processor; its VoltOps sampling setting does not sample the Future AGI copy.
VoltAgent emits its own model spans, so you do not need Vercel AI SDK instrumentation for these calls. Use that integration for AI SDK calls made outside VoltAgent.
View the trace
Open Observe in Future AGI and select my-voltagent-app. Open the weather-agent trace to inspect the model call, get_weather tool call and memory operations. The example associates the trace with conversation-456 and user-123.
| VoltAgent operation | Future AGI span kind |
|---|---|
| Agent or sub-agent | AGENT |
| Model call | LLM |
| Tool call | TOOL |
| Memory read, retriever or vector search | RETRIEVER |
| Embedding | EMBEDDING |
| Memory write, workflow, guardrail or middleware | CHAIN |
Model spans carry model, provider and token attributes when available. Tool spans include the tool name and, unless hidden, arguments and results. Failed model and tool calls retain ERROR status. Sub-agents appear inside their supervisor’s trace under delegate_task.
Tokens are counted once, on model spans. When an operation has exactly one successful generateText or streamText model span, the processor reconciles it with the agent’s total usage across model steps. The agent total stays under voltagent.usage.* rather than being counted again. Open the trace to inspect each model call’s tokens and cost; the trace list’s root-based Tokens column can be empty.
Privacy
Prompts, instructions, message history, tool arguments and results, memory payloads, answers and error text are exported by default. To hide content in the Future AGI copy, set these before initializing the processor:
export FI_HIDE_INPUTS=true
export FI_HIDE_OUTPUTS=true
Alternatively, pass traceConfig: { hideInputs: true, hideOutputs: true } to FIVoltAgentSpanProcessor. Explicit options override environment variables; only the environment value true enables a flag. The finer FI_HIDE_INPUT_MESSAGES, FI_HIDE_OUTPUT_MESSAGES, FI_HIDE_INPUT_TEXT and FI_HIDE_OUTPUT_TEXT flags hide message lists or their text.
Either input or output hiding also removes mixed-content state and free-text error details. Span structure, model, tokens, session, user and error type remain. Use non-sensitive identifiers for userId and conversationId.
- Credential-like attribute keys such as
api_key,secret,password,authorization,cookieandheadersare dropped. This is not a general secret scanner: JSON-valued attributes such asllm.provider_optionscan retain nested credentials. Do not put secrets in provider options, prompts or tool results. - Stack traces are removed and local file paths are rewritten. Error text also has emails and the local user and host names removed, but emails in captured prompts or tool results remain unless you hide that content.
FI_PII_REDACTIONis not applied by this processor. These flags affect only the Future AGI copy, not VoltOps or other exporters receiving the original spans.
Shutdown and serverless
For a short-lived script, keep the VoltAgent instance and call await app.shutdown() in finally, then shut down the Future AGI tracer provider if your code owns it, as above. observability.shutdown() alone does not stop all application resources. The processor flushes its shared exporter but does not close the provider for you.
For a long-running application, perform full shutdown only when stopping the application, not after each request. Before a serverless handler returns, call await observability.forceFlush() after agent work has finished; this exports ended spans without closing the application. On platforms with waitUntil, VoltAgent also supports setWaitUntil(waitUntil) from @voltagent/core for background flushing. A flush does not wait for unfinished work or guarantee delivery if the collector rejects a batch.
Resumed workflows in VoltAgent 2.11.0: a completed resumed workflow can leave a 500 ms polling interval running even after app.shutdown(). Convert a workflow builder with .toWorkflow() once, register and reuse that instance. There is no supported public API to clear the orphaned interval in this version. Only in a short-lived script that still cannot exit, finish application and owned-provider shutdown first, then exit with the actual success or failure status. Do not force-exit a server or manipulate private timers. Ordinary, non-resumed workflows are not affected by this particular issue.
Options and limits
| Processor option | Default | Purpose |
|---|---|---|
tracerProvider | Required unless using exporter | Provider returned by register(); supplies the resource and exporter. |
exporter, resource | Unset | Alternative OpenTelemetry exporter and resource instead of a provider. |
traceConfig | Content captured | Input and output privacy flags. |
batch | true | Batch spans; false sends them individually. |
batchConfig | OTel SDK defaults | Queue size, batch size and export delay. |
usageReconciliationTimeoutMs | 30000 | Maximum wait for the agent’s total usage before exporting a model span. |
generateObjectandstreamObjectopen no model span in VoltAgent 2.11.0, so their usage stays on the agent undervoltagent.usage.*and does not contribute to trace token totals.- Provider-tool routing can create multiple successful model spans in one operation. In that case the processor does not reconcile usage, so earlier model steps can be missing from the total. A flush before the agent span ends, or a reconciliation timeout, can also leave last-step-only usage.
- VoltAgent logs (
RemoteLogProcessor) are not exported by this span processor. Use this setup in Node.js with VoltAgent 2.x, not edge runtimes or VoltAgent 3.x.
Troubleshooting
- No traces: set
FI_PROJECT_NAME,FI_API_KEYandFI_SECRET_KEYbefore initialization.register()requires a project name. Check exporter diagnostics for authentication or collector failures. - Unmapped spans or unexpected content: keep
setGlobalTracerProvider: falseso VoltAgent uses its own provider and the mapping processor runs. - Last spans missing or a script stays open: await completed agent work, then use the full application and owned-provider cleanup shown above. A flush alone is not application shutdown; resumed workflows have the separate 2.11.0 limitation described above.
- Duplicate spans: register the processor only once and avoid sending the same VoltAgent spans through a second exporter to Future AGI.
- Content missing: check
FI_HIDE_*variables and explicittraceConfigoptions. - Provider empty: an OpenAI-compatible provider with a custom ID or a dynamic model may have no recognized provider mapping. Model and token fields can still be recorded.
Questions & Discussion