Skip to content

fix(vercel): keep eve 0.76 agent.step and agent.approval spans as CHAIN - #4007

Open
jimbobbennett wants to merge 3 commits into
mainfrom
fix/vercel-eve-workflow-span-kind
Open

jimbobbennett wants to merge 3 commits into
mainfrom
fix/vercel-eve-workflow-span-kind

Conversation

@jimbobbennett

@jimbobbennett jimbobbennett commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes #4008

Summary

Eve 0.76.0 (published 2026-10-09 17:28 UTC) changed the attributes on its agent.step and agent.approval control-flow spans, and @arizeai/openinference-vercel 3.2.4 classifies them as LLM again. A turn now reports twice as many LLM spans as model calls. The fix that 3.2.3 shipped in #3877 no longer applies to these spans.

Cause

getOISpanKindFromAttributes looks up Eve control-flow spans in EveOperationNameToSpanKindMap by operation.name. Eve 0.76.0 no longer sets operation.name to the span name:

Attribute on agent.step Eve 0.75.1 Eve 0.76.0
operation.name agent.step workflow
gen_ai.operation.name (absent) workflow
resource.name agent.step agent.step
exported openinference.span.kind CHAIN LLM

In Eve's published dist/src/tracing/agent-otel-runtime-context.js (0.76.0), the step span is built with "gen_ai.operation.name": "workflow", ...agentSpanNamingAttributes("agent.step", "workflow"), where agentSpanNamingAttributes(name, op) returns { "operation.name": op, "resource.name": name }. agent-approval-instrumentation.js does the same for agent.approval. Since workflow isn't a key in the Eve map or in GenAIOperationNameToSpanKindMap, the span falls through to the GenAI converter, whose mapSpanKind defaults to LLM for an unrecognized operation.

Fix

When the existing lookups miss and gen_ai.operation.name is workflow, also match resource.name against EveOperationNameToSpanKindMap. See Backward compatibility for the exact conditions.

I also considered mapping gen_ai.operation.name: "workflow" to CHAIN. I didn't, because workflow isn't a GenAI semconv operation value (the spec value is invoke_workflow), and keying on Eve's span identity matches the map's existing purpose.

Backward compatibility

Only Eve 0.76 spans change: those with gen_ai.operation.name=workflow and a resource.name in the Eve map. Every other span classifies exactly as it does on main.

getOISpanKindFromAttributes now checks, in order:

  1. An existing openinference.span.kind (unchanged).
  2. operation.name against the AI SDK map, then the Eve map when the span has no gen_ai.agent.* identity (unchanged).
  3. New: resource.name against the Eve map. This applies only when all of these hold:
    • the earlier lookups missed;
    • the span has no gen_ai.agent.* identity (the same guard as step 2);
    • gen_ai.operation.name is exactly workflow, which is the Eve 0.76 shape. A span with no gen_ai.operation.name never reaches this check.
  4. gen_ai.operation.name against the GenAI map (unchanged), then the GenAI converter's default.

Unchanged:

  • AI SDK spans: operation.name resolves them at step 2, before resource.name (their functionId) is read.
  • Eve 0.75 and earlier: also resolved at step 2.
  • Any span with a recognized gen_ai.operation.name (chat, execute_tool, invoke_agent, decide, and so on): step 3 doesn't apply, so it keeps its GenAI kind.
  • Spans with an agent identity: step 3 doesn't apply, so they still become AGENT.
  • Spans with no gen_ai.operation.name, even if resource.name is agent.step: step 3 doesn't apply, so they keep main's kind.

Tests: new cases in OpenInferenceSpanProcessor.test.ts:

Case Kind
Eve 0.76 agent.step (workflow + resource.name=agent.step) CHAIN
Eve 0.76 agent.approval CHAIN
Eve 0.76 agent.step gets exactly the same OpenInference attributes as Eve 0.75 (parity) CHAIN
Eve 0.75 agent.step with resource.name also set CHAIN
Eve 0.76 shape with gen_ai.agent.name (guard) AGENT
resource.name=agent.step, gen_ai.operation.name=chat, unmapped operation.name (precedence) LLM
resource.name=agent.step, no gen_ai.operation.name, unmapped operation.name LLM
AI SDK ai.generateText whose functionId and resource.name are agent.step AGENT

To show that nothing else changed, I ran the full test file against main's src/utils.ts and src/constants.ts. Only the three Eve 0.76 tests fail there (the two cases and the parity test). Every other new and existing test gives the same result on main and on this branch.

Verification

  • openinference-vercel: 183 tests pass, and type:check, oxlint and oxfmt --check are clean. The branch is rebased onto the latest main (including feat: support AI SDK decision model telemetry #4005).
  • End to end: I ran the Arize AX docs integration harness for Vercel Eve with a raw-attribute dump. Each run used a real Eve dev server, an anthropic/claude-sonnet-4.6 turn with a get_weather tool gated by approval: always() and approved through the session API, and spans exported back from Arize AX. Every run used a fresh scaffold and its own project.

This branch, final version (packed 3.3.0 tarball, workflow-only check):

Eve Runs agent.step agent.approval LLM spans / chat spans
0.76.0 2 CHAIN CHAIN 2 / 2
0.75.1 2 CHAIN CHAIN 2 / 2

Version matrix, run on the previous commit (3b945c2). Versions before 0.76 resolve at the operation.name lookup, which no later commit touches:

Eve Runs agent.step agent.approval agent.action Raw operation.name on agent.*
0.62.0 2 CHAIN (2/2 per run) CHAIN CHAIN span name
0.66.3 2 CHAIN CHAIN CHAIN span name
0.71.3 2 CHAIN CHAIN CHAIN span name
0.75.1 2 CHAIN CHAIN not emitted span name
0.76.0 3 (+1 earlier) CHAIN CHAIN not emitted workflow

In every run, chat spans are LLM, execute_tool is TOOL and invoke_agent is AGENT. The LLM count always equals the chat count (2). Eve 0.62–0.66 start a second invoke_agent trace when the turn resumes after approval; that's Eve behavior and unrelated to this change.

Before the fix (published 3.2.4, no approval tool): Eve 0.75.1 had agent.step as CHAIN in 2/2 runs. Eve 0.76.0 had both agent.step spans as LLM in 7/7 runs (4 LLM spans for 2 chat spans), so the failure is deterministic. The first version of this branch then gave CHAIN in 8/8 runs on 0.76.0.

Review

openinference has no TypeScript reviewer skill, so I applied .agents/skills/python-code-reviewer and .agents/skills/java-code-reviewer to this TypeScript change, adapting the language-specific parts. I also checked .agents/skills/js-docs-sync.

  • Ground truth (both reviewers, step 2). I verified the classification against Eve's published source (dist/src/tracing/*.js in 0.62.0, 0.66.3, 0.71.3, 0.75.1 and 0.76.0) and against raw span attributes captured from real turns. The only shape that sets operation.name/gen_ai.operation.name to workflow is 0.76.0.
  • Medium (exhaustive attribute assertions, 2.3 / Section 2): the new table cases check only the span kind and session.id, so they wouldn't catch extra or missing attributes on the reclassified spans. Resolved: added a parity test that asserts an Eve 0.76 agent.step gets exactly the same attributes as the matching Eve 0.75 span, apart from the two raw operation-name attributes. Real exports agree: on both versions, the only non-Eve attributes on agent.step and agent.approval are openinference.span.kind, session.id and (approvals) tool_call.id.
  • Low (stale wording): the changeset and the EveOperationNameToSpanKindMap comment still described matching resource.name unconditionally. Resolved: both now say it applies only when gen_ai.operation.name is workflow.
  • Low (hardcoded strings, Java Section 3): "resource.name" and "workflow" are string literals. Kept as is: the surrounding lookups ("operation.name", "gen_ai.operation.name") use literals too, and Eve exports no constants for these.
  • Not applicable: tox/Gradle setup, suppression, TraceConfig masking, context propagation and span lifecycle. This change only affects how an already-ended span's kind is derived; it doesn't create spans, wrap calls or add attributes.
  • js-docs-sync: doesn't apply. openinference-vercel has no docs/ folder (only openinference-core does), and the change adds no exports or public API. The README doesn't describe Eve span kinds, so it needs no update.

A second pass over the final diff found nothing further.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6w89c59Ev5pKTN2eqZ9WA

@pkg-pr-new

pkg-pr-new Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@arizeai/openinference-core

npm i https://pkg.pr.new/@arizeai/openinference-core@4007

@arizeai/openinference-genai

npm i https://pkg.pr.new/@arizeai/openinference-genai@4007

@arizeai/openinference-instrumentation-anthropic

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-anthropic@4007

@arizeai/openinference-instrumentation-bedrock

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-bedrock@4007

@arizeai/openinference-instrumentation-bedrock-agent-runtime

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-bedrock-agent-runtime@4007

@arizeai/openinference-instrumentation-beeai

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-beeai@4007

@arizeai/openinference-instrumentation-claude-agent-sdk

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-claude-agent-sdk@4007

@arizeai/openinference-instrumentation-langchain

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-langchain@4007

@arizeai/openinference-instrumentation-langchain-v0

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-langchain-v0@4007

@arizeai/openinference-instrumentation-mcp

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-mcp@4007

@arizeai/openinference-instrumentation-openai

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-openai@4007

@arizeai/openinference-instrumentation-openai-agents

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-openai-agents@4007

@arizeai/openinference-instrumentation-typesafe

npm i https://pkg.pr.new/@arizeai/openinference-instrumentation-typesafe@4007

@arizeai/openinference-semantic-conventions

npm i https://pkg.pr.new/@arizeai/openinference-semantic-conventions@4007

@arizeai/openinference-tanstack-ai

npm i https://pkg.pr.new/@arizeai/openinference-tanstack-ai@4007

@arizeai/openinference-vercel

npm i https://pkg.pr.new/@arizeai/openinference-vercel@4007

commit: e22f98e

jimbobbennett and others added 2 commits October 9, 2026 16:23
eve 0.76 sets operation.name and gen_ai.operation.name to "workflow" on
its agent.step and agent.approval spans and moves the span name to
resource.name. Neither matched the eve span-kind map, so both fell
through to the GenAI converter's LLM default and a turn reported twice
as many LLM spans as model calls. Match resource.name against the map
as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6w89c59Ev5pKTN2eqZ9WA
Apply the resource.name lookup only when gen_ai.operation.name is
missing or "workflow", so a span with a recognized gen_ai operation
keeps its kind. Add tests for the agent-identity guard, gen_ai
precedence, an AI SDK span whose functionId is agent.step, and the eve
0.75 shape with resource.name set, and set operation.name explicitly on
the eve 0.76 cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6w89c59Ev5pKTN2eqZ9WA
@jimbobbennett
jimbobbennett force-pushed the fix/vercel-eve-workflow-span-kind branch from c3eed7a to 3b945c2 Compare October 9, 2026 23:25
…orkflow

Drop the missing-operation case so only eve 0.76 spans classify
differently from before. Add a test for a span with resource.name
agent.step and no gen_ai operation, and a parity test that an eve 0.76
agent.step gets the same OpenInference attributes as an eve 0.75 one.
Update the changeset and the eve map comment to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6w89c59Ev5pKTN2eqZ9WA
@jimbobbennett
jimbobbennett marked this pull request as ready for review October 10, 2026 00:06
@jimbobbennett
jimbobbennett requested a review from a team as a code owner October 10, 2026 00:06

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[bug] openinference-vercel: Eve 0.76 agent.step / agent.approval spans classified as LLM again (regression of #3876)

1 participant