Pi Coding Agent SDK tracing with Future AGI
Trace Pi Coding Agent SDK runs, turns, model calls, tools, and compaction with @traceai/pi-coding-agent. Prompt, code, and error text stay off by default.
Trace your Pi Coding Agent SDK sessions with the maintained @traceai/pi-coding-agent package. Each agent run becomes a Future AGI trace with turns, model calls, token usage, tools, and context compaction.
This guide is for Node.js applications that call createAgentSession(). For interactive terminal sessions, use the Pi CLI guide or the separate Oh My Pi guide.
Prerequisites
- Node.js 22.19 or newer.
- Future AGI API and secret keys from Settings → API Keys.
- A model configured in Pi with your own provider credentials. The SDK uses Pi’s configuration in
~/.pi/agent, orPI_CODING_AGENT_DIRwhen set. See Pi model configuration for provider keys and custom endpoints.
Note
Use only one tracing integration for each session. If the Pi CLI extension (futureagi-otlp.ts) is installed and your SDK application binds extensions, disable that extension for the SDK process to avoid duplicate traces. See Troubleshooting.
1. Install
npm install @traceai/pi-coding-agent@0.1.0 @traceai/fi-core@1.1.1 @earendil-works/pi-coding-agent@1.2.0
Pi’s current npm scope is @earendil-works/*; do not install the older @mariozechner/pi-coding-agent package for this example.
2. Configure Future AGI
export FI_API_KEY="your-futureagi-api-key"
export FI_SECRET_KEY="your-futureagi-secret-key"
export FI_PROJECT_NAME="my-pi-agent"
The keys authenticate the exporter and are not added to spans. For self-hosted Future AGI, also set FI_BASE_URL to your collector’s base URL, for example http://localhost:4318. The exporter appends /tracer/v1/traces.
If you store these variables in a local .env file, load it with node --env-file=.env app.mjs; Node does not load it automatically. Keep credentials out of source control.
3. Trace a session
Save this as app.mjs. Wrap createAgentSession() once and create sessions through the wrapper. The example enables only the read and ls tools; run it in a project you want the model to inspect.
import { register, ProjectType } from "@traceai/fi-core";
import { createAgentSession, SessionManager } from "@earendil-works/pi-coding-agent";
import { PiCodingAgentInstrumentation } from "@traceai/pi-coding-agent";
const tracerProvider = register({ projectType: ProjectType.OBSERVE });
const instrumentation = new PiCodingAgentInstrumentation({ tracerProvider });
const createTracedSession = instrumentation.wrapCreateAgentSession(createAgentSession);
let session;
try {
({ session } = await createTracedSession({
sessionManager: SessionManager.inMemory(),
tools: ["read", "ls"],
}));
await session.prompt("List the files in this folder and read README.md");
console.log(session.getLastAssistantText() ?? "");
const last = session.messages.findLast((message) => message.role === "assistant");
if (last?.stopReason === "error" || last?.stopReason === "aborted") {
process.exitCode = 1;
}
} finally {
session?.dispose();
await tracerProvider.shutdown();
}
Run it with your Pi model credentials available in the same process:
node app.mjs
The runnable application example also accepts a prompt argument, PI_CWD, and an explicit PI_PROVIDER / PI_MODEL. From that example directory, run npm install, then node trace_session.mjs "List the files here".
4. Open the trace
In Future AGI, open Observe, select my-pi-agent, and open the newest invoke_agent pi trace. Runs from the same Pi session share session.id and group under Sessions.
invoke_agent pi
├── pi.turn
│ ├── chat <model>
│ └── execute_tool ls
├── pi.turn
│ ├── chat <model>
│ └── execute_tool read
└── pi.turn
└── chat <model>
The exact number of turns and tool calls depends on the model’s response. A pi.compaction span appears when Pi compacts context.
What is captured
| Span | Captured by default |
|---|---|
invoke_agent pi (AGENT) | Session ID, attempt and retry counts, turn/model/tool counts, run token and cost totals under pi.agent.*, retry events |
pi.turn (CHAIN) | Turn index, stop reason, tool-result count |
chat <model> (LLM) | Model, provider, response ID, token counts including cached tokens, priced cost, finish reason, tool names, request timing |
execute_tool <tool> (TOOL) | Tool name, call ID, duration, error flag; nested tools are children of their calling tool |
pi.compaction (CHAIN) | Compaction reason, tokens before and estimated after, summarization token usage and cost |
Compaction during a run is a child of that run. session.compact() outside a run creates a separate trace in the same session. Run totals use pi.agent.*, not gen_ai.usage.*, so they do not duplicate the child spans’ token counts.
Failed or aborted model calls and their turns have ERROR status. A run is ERROR if it ends aborted or its last model call failed; a successful retry leaves the failed call’s span as ERROR and the run as OK. Failed tools and compactions also have ERROR status. By default, error spans retain error.type but have no status message. Disposing a session mid-run closes open spans with pi.incomplete=true.
Privacy
Prompts, tool arguments, tool results, assistant text, session names, compaction summaries, and error text are hidden by default. Structure and metadata such as session IDs, model/provider names, tool names, token counts, durations, status codes, and error.type remain visible.
Content capture and error details have independent controls:
| Setting | When set to false |
|---|---|
FI_HIDE_INPUTS / hideInputs | Captures prompts on run spans, tool arguments, tool-call arguments, and session names |
FI_HIDE_OUTPUTS / hideOutputs | Captures successful assistant output, tool results, and compaction summaries; does not enable error text by itself |
FI_HIDE_ERROR_DETAILS / hideErrorDetails | Enables error status messages. With outputs still hidden, messages contain only a limited summary; raw provider, failed-tool, and compaction error text requires both hideOutputs: false and hideErrorDetails: false |
To capture ordinary content while keeping error details hidden, set these variables before starting the application:
export FI_HIDE_INPUTS=false
export FI_HIDE_OUTPUTS=false
export FI_HIDE_ERROR_DETAILS=true
To include raw error text as well, also set FI_HIDE_ERROR_DETAILS=false. Error messages can contain request fragments, account details, source code, and local paths. Enable this only for data you intend to send to Future AGI.
Alternatively, configure the instrumentation explicitly:
const instrumentation = new PiCodingAgentInstrumentation({
tracerProvider,
traceConfig: {
hideInputs: false,
hideOutputs: false,
hideErrorDetails: true, // Keep error text hidden independently of outputs.
},
});
Only the environment value false (case-insensitive, surrounding spaces ignored) enables each capture option. Explicit traceConfig values take precedence. Captured content is truncated at 16,384 characters by default (maxContentLength); raw error status text is truncated at 1,000 characters.
The instrumentation does not read the system prompt or add the working directory as an attribute. When content capture is enabled, file paths and source code can still appear in prompts, tool arguments, and results. These controls affect this instrumentation’s spans, not the data Pi sends to your model provider.
Existing sessions and compatibility
If another component creates the session, subscribe before the first prompt:
const stop = instrumentation.instrumentSession(session);
// Later, stop tracing this session:
stop();
A session is traced once: repeated instrumentSession() calls return the same stop function until tracing stops. An AgentSessionRuntime creates a new session on new, resume, fork, or import; call instrumentSession(runtime.session) again after each replacement.
Pi 0.80.5 and later emit agent_settled, which preserves one trace across retries and continuations. Older versions end the trace at an agent_end without an announced retry, so continuations can split into separate traces. Use the Pi version in the install command for this guide.
Session events do not expose the full model request, system prompt, streaming deltas, time to first token, or compaction model identity. Cost appears only when Pi has pricing for the model; custom models without prices have no cost attribute.
Troubleshooting
No trace appears. Check FI_API_KEY, FI_SECRET_KEY, and FI_PROJECT_NAME in the Node process. For self-hosting, check FI_BASE_URL. Instrument before calling prompt() and await tracerProvider.shutdown() before a short script exits.
Every prompt appears twice. Disable the Pi CLI tracing extension for SDK sessions. To keep other extensions, supply a resource loader that excludes only futureagi-otlp.ts:
import { DefaultResourceLoader, getAgentDir } from "@earendil-works/pi-coding-agent";
const resourceLoader = new DefaultResourceLoader({
cwd: process.cwd(),
agentDir: getAgentDir(),
extensionsOverride: (base) => ({
...base,
extensions: base.extensions.filter((extension) => !extension.path.endsWith("futureagi-otlp.ts")),
}),
});
await resourceLoader.reload();
// Pass resourceLoader to createTracedSession() in your application.
Every model call appears twice. Do not instrument Pi’s provider SDK calls separately in the same process. This package already traces model calls from Pi’s session events.
Error text is missing even though outputs are enabled. Error details are hidden independently. Keep that privacy default unless you intend to export them; see Privacy for the two settings required for raw error text.
The run is not a child of my request span. Register an OpenTelemetry context manager in your application before creating the active request span. Without one, Pi runs start their own traces.
Questions & Discussion