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 operationFuture AGI span kind
Agent or sub-agentAGENT
Model callLLM
Tool callTOOL
Memory read, retriever or vector searchRETRIEVER
EmbeddingEMBEDDING
Memory write, workflow, guardrail or middlewareCHAIN

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, cookie and headers are dropped. This is not a general secret scanner: JSON-valued attributes such as llm.provider_options can 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_REDACTION is 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 optionDefaultPurpose
tracerProviderRequired unless using exporterProvider returned by register(); supplies the resource and exporter.
exporter, resourceUnsetAlternative OpenTelemetry exporter and resource instead of a provider.
traceConfigContent capturedInput and output privacy flags.
batchtrueBatch spans; false sends them individually.
batchConfigOTel SDK defaultsQueue size, batch size and export delay.
usageReconciliationTimeoutMs30000Maximum wait for the agent’s total usage before exporting a model span.
  • generateObject and streamObject open no model span in VoltAgent 2.11.0, so their usage stays on the agent under voltagent.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_KEY and FI_SECRET_KEY before initialization. register() requires a project name. Check exporter diagnostics for authentication or collector failures.
  • Unmapped spans or unexpected content: keep setGlobalTracerProvider: false so 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 explicit traceConfig options.
  • 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.
Was this page helpful?

Questions & Discussion