Check out the newest way to compare different models for a task/agent harness: AutoEvals
Agent Frameworks

Traces

Pi Agent Traces

Trace current Pi Agent model turns, streams, tool calls, usage, costs, and agent identity through the Inference platform.

Using legacy @mariozechner/pi-ai? Use the PI AI integration.

Inference platform instruments current Pi Agent applications built with @earendil-works/pi-agent-core and @earendil-works/pi-ai. Each Pi Models collection owns its providers. Pass that collection to the Inference platform so each model turn emits an OpenInference LLM span.

This guide is tested with @earendil-works/pi-agent-core@0.84.1 and @earendil-works/pi-ai@0.84.1.

Pi Agent is available for TypeScript. There is no Python equivalent for this integration.

What Is Captured

  • One LLM span per model turn, named like pi-agent.<provider>.turn
  • Calls through stream, streamSimple, complete, and completeSimple
  • System prompts, input messages, assistant output, model name, and provider
  • Tool call IDs, names, and JSON arguments from assistant messages
  • Token usage, prompt cache read/write counts, finish reason, and total cost
  • Errors, aborts, and exception details
  • Active agentSpan() identity, including agent.id, agent.name, agent.role, and session.id

Install

TypeScript
bun add @inference/tracing@0.1.9 @earendil-works/pi-agent-core@0.84.1 @earendil-works/pi-ai@0.84.1

Configure Export

Set the Inference Tracing endpoint and token before your app starts. Generate a token at API Keys.

export INFERENCE_OTLP_ENDPOINT="https://telemetry.inference.net"
export INFERENCE_API_KEY="<your-token>"
export INFERENCE_SERVICE_NAME="pi-agent"

export ANTHROPIC_API_KEY="<your-anthropic-api-key>"

Initialize Tracing

Create the Pi Models collection before tracing setup. Pass the collection as piAgent. You can add providers before or after setup.

TypeScript
import { createModels } from "@earendil-works/pi-ai";
import { anthropicProvider } from "@earendil-works/pi-ai/providers/anthropic";
import { setup } from "@inference/tracing";

const models = createModels();
const tracing = await setup({
  serviceName: process.env.INFERENCE_SERVICE_NAME ?? "pi-agent",
  autoInstrument: false,
  modules: { piAgent: models },
});

models.setProvider(anthropicProvider());

Pi uses a separate Models collection for each application. Inference platform cannot find that collection through package auto-detection. Pass it as modules.piAgent or call instrumentPiAgent(models, tracing).

For manual initialization, use the Pi Agent subpath helper before the agent makes its first model call.

TypeScript
import { createModels } from "@earendil-works/pi-ai";
import { setup } from "@inference/tracing";
import { instrumentPiAgent } from "@inference/tracing/pi-agent";

const models = createModels();
const tracing = await setup({ autoInstrument: false });
instrumentPiAgent(models, tracing);

Run An Agent

Pass models.streamSimple.bind(models) to the current Pi Agent. Wrap the run in agentSpan() to group all model turns under one stable agent identity.

The following example uses an Anthropic model. It assumes you ran the setup block above.

TypeScript
import { Agent } from "@earendil-works/pi-agent-core";
import { agentSpan } from "@inference/tracing";

const model = models.getModel("anthropic", "claude-sonnet-4-6");
if (!model) throw new Error("Pi model not found");

const agent = new Agent({
  initialState: {
    systemPrompt: "You answer order questions in one short sentence.",
    model,
  },
  sessionId: "order-abc-123",
  streamFn: models.streamSimple.bind(models),
});

await agentSpan(
  {
    agentId: "pi-support-agent",
    agentName: "Pi Support Agent",
    spanName: "pi-support-agent.run",
    sessionId: "order-abc-123",
    role: "support",
    system: "pi-agent",
  },
  async (span) => {
    const input = "Summarize order ABC-123.";
    span.setInput(input);
    await agent.prompt(input);
    span.setOutput(agent.state.messages.at(-1));
  },
);

await tracing.shutdown();

Expected spans:

  • pi-support-agent.run AGENT span
  • One or more pi-agent.anthropic.turn LLM child spans

Trace Tool Execution

Pi returns model tool calls in assistant messages and executes AgentTool functions locally. Inference platform records the requested tool name, ID, and arguments on the LLM span. Wrap local execution with manualSpan() when you also want a TOOL span for the work.

TypeScript
import { type AgentTool } from "@earendil-works/pi-agent-core";
import { Type } from "@earendil-works/pi-ai";
import { manualSpan, SpanKindValues } from "@inference/tracing";

const parameters = Type.Object({ orderId: Type.String() });

const lookupOrder: AgentTool<typeof parameters> = {
  name: "lookup_order",
  label: "Look up order",
  description: "Look up an order by ID.",
  parameters,
  execute: async (toolCallId, { orderId }) =>
    manualSpan(
      {
        spanName: "lookup_order",
        spanKind: SpanKindValues.TOOL,
        toolName: "lookup_order",
        toolCallId,
        input: { orderId },
      },
      async (span) => {
        const order = { orderId, status: "shipped", eta: "Friday" };
        span.setOutput(order);
        return {
          content: [{ type: "text" as const, text: JSON.stringify(order) }],
          details: order,
        };
      },
    ),
};

Add lookupOrder to initialState.tools. A tool round trip then produces:

  • A pi-agent.<provider>.turn LLM span with the requested tool call
  • A lookup_order TOOL span for local execution
  • Another pi-agent.<provider>.turn LLM span for the final answer

Verify in the Inference platform

Filter traces by your service.name, for example pi-agent. A successful run shows the AGENT span with nested Pi Agent LLM spans. Each LLM span includes input/output, model metadata, usage, finish reason, and tool call attributes.

If no Pi Agent spans appear:

  • Pass the Models collection as modules: { piAgent: models }.
  • Instrument the collection before the agent makes its first model call.
  • Add providers through the instrumented collection's setProvider() method.
  • Consume streaming results or await agent.prompt() before shutdown.
  • Call await tracing.shutdown() before a short-lived process exits.

On this page