> ## Documentation Index
> Fetch the complete documentation index at: https://arize-ax.mintlify.site/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel Eve

> Trace Vercel Eve agents with OpenInference and send AI SDK spans to Arize AX for LLM and agent observability.

[Eve](https://eve.dev/) is Vercel's filesystem-first TypeScript framework for durable backend AI agents — you define an agent as files under an `agent/` directory and Eve compiles it into an app that runs on Vercel Functions. Eve emits [Vercel AI SDK](https://github.com/vercel/ai) OpenTelemetry spans for every turn, model call, and tool execution. Arize AX captures them by registering the [`@arizeai/openinference-vercel`](https://github.com/Arize-ai/openinference/tree/main/js/packages/openinference-vercel) span processor in Eve's `agent/instrumentation.ts`.

## Prerequisites

* Node.js 24+ (Eve's CLI requires it)
* An Eve agent project (`npx eve@latest init my-agent`)
* An Arize AX account ([sign up](https://arize.com/sign-up/))
* An AI Gateway credential for Eve's model routing — an `AI_GATEWAY_API_KEY`, or a `VERCEL_OIDC_TOKEN` pulled with `vercel link`

## Launch Arize AX

1. Sign in to your [Arize AX account](https://app.arize.com/).
2. From **Space Settings**, copy your **Space ID** and **API Key**. You will set them as `ARIZE_SPACE_ID` and `ARIZE_API_KEY` below.

## Install

In your Eve project, add the Arize OpenInference processor and the OpenTelemetry packages it exports through:

```bash theme={null}
npm install @arizeai/openinference-vercel@^3 \
  @arizeai/openinference-semantic-conventions \
  @vercel/otel \
  @opentelemetry/api \
  @opentelemetry/exporter-trace-otlp-proto
```

## Configure credentials

```bash theme={null}
export ARIZE_SPACE_ID="<your-space-id>"
export ARIZE_API_KEY="<your-api-key>"
export AI_GATEWAY_API_KEY="<your-ai-gateway-key>"
```

## Setup tracing

Eve auto-discovers `agent/instrumentation.ts` and runs it once at server startup, before any agent code. Its presence enables telemetry — there is no separate toggle, and you do not set `experimental_telemetry` on individual calls (Eve manages that internally). Register an OpenTelemetry provider in the `setup` callback, which receives the resolved agent name. The processor's `spanFilter` and `reparentOrphanedSpans` options control which spans reach Arize and how each trace is rooted — see [Span filter](#span-filter):

```typescript theme={null}
// agent/instrumentation.ts
import { defineInstrumentation } from "eve/instrumentation";
import { registerOTel } from "@vercel/otel";
import {
  isOpenInferenceSpan,
  OpenInferenceSimpleSpanProcessor,
} from "@arizeai/openinference-vercel";
import { SEMRESATTRS_PROJECT_NAME } from "@arizeai/openinference-semantic-conventions";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";

export default defineInstrumentation({
  setup: ({ agentName }) => {
    // Route to the project named by ARIZE_PROJECT_NAME (falling back to the agent
    // name), matching the ARIZE_PROJECT_NAME convention used across the Arize docs.
    const projectName = process.env.ARIZE_PROJECT_NAME ?? agentName;
    return registerOTel({
      serviceName: projectName,
      // Arize routes spans to a project by the project-name resource attribute —
      // without it the OTLP endpoint rejects spans with an InvalidArgument error.
      attributes: { [SEMRESATTRS_PROJECT_NAME]: projectName },
      spanProcessors: [
        new OpenInferenceSimpleSpanProcessor({
          exporter: new OTLPTraceExporter({
            url: "https://otlp.arize.com/v1/traces",
            headers: {
              "arize-space-id": process.env.ARIZE_SPACE_ID ?? "",
              "arize-api-key": process.env.ARIZE_API_KEY ?? "",
            },
          }),
          spanFilter: isOpenInferenceSpan,
          reparentOrphanedSpans: true,
        }),
      ],
    });
  },
});
```

<Note>
  `OpenInferenceSimpleSpanProcessor` exports each span synchronously as it ends, so it is safe on the short-lived serverless functions Eve runs on (no process-exit `forceFlush` to call). `@arizeai/openinference-vercel` translates the AI SDK spans into OpenInference before export.
</Note>

## Run Eve

Start the Eve dev server, then open a session against the built-in HTTP channel:

```bash theme={null}
npm run dev
```

The dev server listens on `http://127.0.0.1:2000` by default (pass `--port` to change it). Open a session against the built-in HTTP channel:

```bash theme={null}
curl -X POST http://127.0.0.1:2000/eve/v1/session \
  -H 'content-type: application/json' \
  -d '{"message":"What is the weather in Brooklyn?"}'
```

The response returns a `continuationToken` in the body and an `x-eve-session-id` header. Stream the session's lifecycle events to watch the turn complete:

```bash theme={null}
curl http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream
```

### Expected output

```text wrap theme={null}
{"type":"session.started","data":{"runtime":{"agentName":"weather-agent"}}}
{"type":"actions.requested","data":{"actions":[{"kind":"tool-call","toolName":"get_weather","input":{"city":"Brooklyn"}}]}}
{"type":"message.completed","data":{"message":"The weather in Brooklyn is **sunny** and **72°F**.","finishReason":"stop"}}
```

## Verify in Arize AX

1. Open your Arize AX space and select the project named after your agent (the project-name resource attribute above).
2. Within \~30 seconds you should see the turn's spans. Eve runs on the AI SDK's GenAI-convention spans, so every span arrives named `gen_ai` (or `gen_ai.client` for the model request) rather than `ai.streamText`/`ai.toolCall` — read the OpenInference **span kind** to tell them apart. Each step is an **agent** span over a **llm** span; the model request is a `gen_ai.client` **llm** span (prompt, response, token usage), and each tool run is a `gen_ai` **tool** span carrying `tool.name` (for example `get_weather`). All of a turn's steps nest under Eve's `ai.eve.turn` workflow span, which `reparentOrphanedSpans` re-roots and tags as an **agent** span so it anchors the turn as a clean per-turn root.
3. Eve attaches session context to the spans under the `ai.settings.context.eve.*` prefix — `ai.settings.context.eve.session.id`, `ai.settings.context.eve.turn.id`, `ai.settings.context.eve.step.index`, and `ai.settings.context.eve.channel.kind` — so you can group a trace back to its session.
4. If no traces appear, see [Troubleshooting](#troubleshooting).

<Frame caption="A Vercel Eve turn trace in Arize AX. With reparentOrphanedSpans enabled, ai.eve.turn becomes an agent root over the per-step agent, llm, and tool spans.">
  ![Arize AX trace view of a Vercel Eve agent turn, showing the ai.eve.turn agent root span with nested agent, llm, and tool spans for each step](https://storage.googleapis.com/arize-phoenix-assets/assets/images/arize-docs-images/cookbooks/vercel-eve-trace.png)
</Frame>

### Check from the skill, CLI, or SDK

Confirm spans are actually reaching your Arize AX project. Use whichever fits your workflow — the skill and CLI work for any framework; the SDK check is shown for each language.

<Tabs>
  <Tab title="Arize skill (agent)">
    Install the [Arize Skills](https://github.com/Arize-ai/arize-skills) plugin and let your coding agent check for you:

    ```bash theme={null}
    npx skills add Arize-ai/arize-skills
    ```

    Then prompt your agent:

    > Use the `arize-trace` skill to export and analyze recent traces from my project. Confirm spans are arriving, and summarize any errors or latency issues.
  </Tab>

  <Tab title="AX CLI">
    Export recent spans for your project — any rows mean traces are landing:

    ```bash theme={null}
    ax spans export "$ARIZE_PROJECT_NAME" --space "$ARIZE_SPACE_ID" \
      --limit 5 --stdout | jq 'length'
    ```

    A non-zero count confirms spans reached Arize AX. Run `ax auth login` first if you have not authenticated. See the [`ax spans` reference](/api-clients/cli/spans).
  </Tab>

  <Tab title="SDK">
    Query the project's spans and check that at least one came back.

    <CodeGroup>
      ```python Python theme={null}
      import os
      from arize import ArizeClient

      client = ArizeClient(api_key=os.environ["ARIZE_API_KEY"])
      resp = client.spans.list(
          project=os.environ["ARIZE_PROJECT_NAME"],
          space=os.environ["ARIZE_SPACE_ID"],
          limit=5,
      )
      count = len(resp.spans)
      print(
          f"{count} span(s) found" if count else "No spans yet — recheck setup"
      )
      ```

      ```typescript TypeScript theme={null}
      // Reads ARIZE_API_KEY from the environment.
      import { listSpans } from "@arizeai/ax-client";

      const { data: spans } = await listSpans({
        project: process.env.ARIZE_PROJECT_NAME!,
        space: process.env.ARIZE_SPACE_ID!,
        limit: 5,
      });
      const count = spans.length;
      console.log(
        count ? `${count} span(s) found` : "No spans yet — recheck setup",
      );
      ```

      ```go Go theme={null}
      client, err := arize.NewClient(
          arize.Config{APIKey: os.Getenv("ARIZE_API_KEY")},
      )
      if err != nil {
          log.Fatal(err)
      }
      resp, err := client.Spans.List(ctx, spans.ListRequest{
          Project: os.Getenv("ARIZE_PROJECT_NAME"),
          Space:   os.Getenv("ARIZE_SPACE_ID"),
          Limit:   5,
      })
      if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("%d span(s) found\n", len(resp.Spans))
      ```
    </CodeGroup>

    SDK span references: [Python](/api-clients/python/version-8/client-resources/spans) · [TypeScript](/api-clients/typescript/version-1/client-resources/spans) · [Go](/api-clients/go/version-2/client-resources/spans).
  </Tab>
</Tabs>

## Span filter

Two options on the processor control which spans reach Arize and how they're rooted:

* **`spanFilter: isOpenInferenceSpan`** keeps only the AI spans and drops the rest — the raw HTTP/fetch spans and Eve's Vercel Workflow spans.
* **`reparentOrphanedSpans: true`** re-roots any AI span left orphaned when the filter drops its parent, so it no longer points at a parent that was never exported. It also recognizes Eve's `ai.eve.turn` wrapper as an AI-like root and tags it `openinference.span.kind = AGENT`, so each turn shows up as a single clean **agent** root with its steps nested underneath.

```typescript theme={null}
new OpenInferenceSimpleSpanProcessor({
  exporter,
  spanFilter: isOpenInferenceSpan,
  reparentOrphanedSpans: true, // default: false
});
```

## Troubleshooting

* **No traces in Arize AX.** Confirm the file is exactly `agent/instrumentation.ts` (Eve discovers it by path), and that `ARIZE_SPACE_ID` and `ARIZE_API_KEY` are set in the shell running `npm run dev`. Enable OpenTelemetry debug logs with `export OTEL_LOG_LEVEL=debug` and re-run.
* **Model auth errors.** Eve routes models through AI Gateway — set `AI_GATEWAY_API_KEY`, or run `vercel link` to use a `VERCEL_OIDC_TOKEN`. To skip the gateway, switch the agent to a direct provider model (e.g. `@ai-sdk/openai` with `OPENAI_API_KEY`). A brand-new AI Gateway key also fails until you add a payment method — the turn errors with `GatewayInternalServerError: AI Gateway requires a valid credit card on file to service requests`, even if you only plan to use the free credits. Add a card in your Vercel **AI Gateway** dashboard to unlock them.
* **Version mismatch.** Pin the OpenTelemetry packages to Eve's `@vercel/otel` major: `@vercel/otel@1.x` requires `@opentelemetry/*` `1.x`; `@vercel/otel@2.x` requires `2.x`. Mismatches surface as silently missing traces.
* **`gen_ai` spans orphaned on the Traces tab.** This happens when `spanFilter: isOpenInferenceSpan` drops Eve's `ai.eve.turn` workflow span without re-rooting its children, leaving the per-step `gen_ai` spans with no parent. Set `reparentOrphanedSpans: true` as shown in [Setup tracing](#setup-tracing) for a single clean agent root per turn, and confirm `@arizeai/openinference-vercel` is **3.0.0 or later** (the v3 major maps Eve's v7 GenAI-convention spans and carries the `ai.eve.turn` reparenting fix first shipped in 2.8.1).

## Resources

<CardGroup>
  <Card icon="book" href="/ax/cookbooks/instrument/tracing-a-vercel-eve-agent" title="Cookbook: Tracing a Vercel Eve Agent" horizontal />

  <Card icon="book-open" href="https://vercel.com/docs/eve/observability" title="Eve Observability Docs" horizontal />

  <Card icon="terminal" href="https://github.com/Arize-ai/openinference/tree/main/js/packages/openinference-vercel" title="OpenInference Vercel Span Processor" horizontal />

  <Card icon="robot" href="https://eve.dev/docs/getting-started" title="Eve Getting Started" horizontal />
</CardGroup>
