Skip to content

Conversation

@nirga
Copy link
Member

@nirga nirga commented Nov 23, 2025

Summary

Adds automatic agent detection when using Vercel AI SDK with agent metadata, following the Python OpenLLMetry reference implementation.

Changes

  • Enhanced transformTelemetryMetadata(): Auto-detects agent metadata key
  • Automatic span classification: Sets traceloop.span.kind: "agent" when detected
  • Sets agent name: Adds gen_ai.agent.name attribute
  • Preserves metadata: All metadata saved as traceloop.association.properties.*
  • Tests: 2 comprehensive unit tests for agent detection
  • Sample apps: 2 demo applications showing agent usage

Example Usage

await generateText({
  model: openai("gpt-4o"),
  messages: [...],
  experimental_telemetry: {
    isEnabled: true,
    metadata: {
      agent: "research_assistant",
      sessionId: "session_123",
      userId: "user_456",
    },
  },
});

Resulting Attributes

{
  "gen_ai.agent.name": "research_assistant",
  "traceloop.span.kind": "agent",
  "traceloop.association.properties.agent": "research_assistant",
  "traceloop.association.properties.sessionId": "session_123",
  "traceloop.association.properties.userId": "user_456"
}

Testing

All tests passing:

  • ✅ Agent detection when agent metadata present
  • ✅ No false positives when agent metadata absent
  • ✅ Association properties correctly preserved

Files Changed

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (+15 lines)
  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (+53 lines)
  • packages/sample-app/package.json (+2 lines)
  • packages/sample-app/src/sample_vercel_ai_agent.ts (new file)
  • packages/sample-app/src/sample_vercel_ai_agent_simple.ts (new file)

Total: 5 files changed, 613 insertions(+)

Related

  • Follows Python OpenLLMetry agent instrumentation pattern
  • Uses existing gen_ai.agent.name attribute (added in #XXX by @galkleiman)
  • Compatible with OpenTelemetry GenAI Semantic Conventions

🤖 Generated with Claude Code


Important

Adds agent detection to AI SDK, enhancing telemetry metadata transformation and span classification, with new tests and sample apps.

  • Behavior:
    • Enhances transformTelemetryMetadata() in ai-sdk-transformations.ts to auto-detect agent metadata key and set gen_ai.agent.name attribute.
    • Sets traceloop.span.kind: "agent" for root AI spans when agent metadata is detected.
    • Preserves all metadata as traceloop.association.properties.*.
  • Span Processing:
    • Updates span-processor.ts to propagate agent names across spans and clean up expired trace agent names.
    • Adds isRootSpan() and cleanupExpiredTraceAgentNames() functions.
  • Testing:
    • Adds ai-sdk-agent-integration.test.ts to test agent name propagation and span behavior.
    • Updates ai-sdk-transformations.test.ts with tests for agent metadata handling.
  • Sample Apps:
    • Adds sample_vercel_ai_agent.ts and sample_vercel_ai_agent_simple.ts to demonstrate agent usage with session logging and telemetry.

This description was created by Ellipsis for 3440e2c. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Added two sample agents (research-style and simple task/calculator) with session logging, in-memory tools, and telemetry.
    • Tracing now propagates agent identity across spans, marks root agent spans, and labels tool-call spans with entity names.
  • Tests

    • Added unit and integration tests for agent metadata propagation, root-vs-child span behavior, and tool-call tracing attributes; includes new recorded test artifact.
  • Chores

    • Added runnable scripts to build and run the sample agents.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds automatic agent detection when using Vercel AI SDK with agent metadata,
following the Python OpenLLMetry reference implementation.

**Changes:**
- Enhanced `transformTelemetryMetadata()` to detect `agent` metadata key
- Auto-sets `gen_ai.agent.name` and `traceloop.span.kind: "agent"` when detected
- Preserves all metadata as `traceloop.association.properties.*`
- Added 2 comprehensive tests for agent detection
- Added 2 sample agent applications demonstrating usage

**Example Usage:**
```typescript
await generateText({
  model: openai("gpt-4o"),
  messages: [...],
  experimental_telemetry: {
    isEnabled: true,
    metadata: {
      agent: "research_assistant",
      sessionId: "session_123",
    },
  },
});
```

**Resulting Attributes:**
- `gen_ai.agent.name`: "research_assistant"
- `traceloop.span.kind`: "agent"
- `traceloop.association.properties.agent`: "research_assistant"
- `traceloop.association.properties.sessionId`: "session_123"

All tests passing (5/5 agent tests).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 23, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds two sample Vercel AI agents and npm scripts; implements span-name propagation, agent-name and tool-span attribute handling in tracing transforms; stores and propagates agent names per-trace in the span processor; and adds tests plus a HAR recording validating agent/tool behaviors.

Changes

Cohort / File(s) Summary
Package scripts
packages/sample-app/package.json
Added run:vercel_agent and run:vercel_agent_simple scripts to build and run the new sample agents.
Research agent sample
packages/sample-app/src/sample_vercel_ai_agent.ts
New research agent module with in-memory knowledge base & memory, toolset (searchKnowledge, analyzeTrends, generateReport, saveToMemory, recallFromMemory), per-session conversation history, traceloop.withWorkflow telemetry integration, and demo main.
Simple agent sample
packages/sample-app/src/sample_vercel_ai_agent_simple.ts
New simple agent with calculator and task-management tools, zod-validated inputs, in-memory task store, tool handlers, telemetry wiring, workflow runner, and demo main.
Tracing transformations
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
Added optional spanName parameter to transformTelemetryMetadata and transformLLMSpans, propagate span.name into transformations, set GEN_AI_AGENT_NAME for agent metadata, mark root AI spans (run.ai) as agent-kind and set TRACELOOP_ENTITY_NAME, and mark tool calls with TRACELOOP_SPAN_KIND = "tool" plus entity input/output mapping; imported TraceloopSpanKindValues.
Span processor: agent propagation
packages/traceloop-sdk/src/lib/tracing/span-processor.ts
Introduced per-trace in-memory map to cache agent names (with TTL and cleanup), detect root spans, store agent names when root spans end, propagate stored agent names to child spans lacking them, and remove entries when root span ends.
Tests: transformations & integration
packages/traceloop-sdk/test/ai-sdk-transformations.test.ts, packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
Added tests validating root vs child span agent metadata behavior, tool-call attribute transformations (input/output mapping, span kind and entity name), end-to-end agent integration asserting spans, kinds, and association properties.
Dev deps & recording
packages/traceloop-sdk/package.json, packages/traceloop-sdk/recordings/.../recording.har
Added zod to devDependencies and added HAR recording artifact for a tool-call test (function call to calculate).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant ResearchAgent
    participant Traceloop as traceloop.withWorkflow
    participant LLM as generateText (GPT-4o)
    participant Tools as Tools (search/analyze/report)
    participant Memory as AgentMemory

    User->>ResearchAgent: demonstrateAgent(userId)
    ResearchAgent->>ResearchAgent: init session & history
    ResearchAgent->>Traceloop: withWorkflow(telemetry)
    Traceloop->>LLM: generateText(prompt, tools, metadata)
    LLM->>Tools: call analyzeTrends
    Tools->>Memory: save analysis
    Memory-->>Tools: stored result
    Tools-->>LLM: tool result
    LLM-->>Traceloop: assistant response
    Traceloop-->>ResearchAgent: response (added to history)
    ResearchAgent-->>User: reply + metadata
Loading
sequenceDiagram
    autonumber
    participant main
    participant SimpleAgent as runSimpleAgent
    participant Traceloop as traceloop.withWorkflow
    participant LLM as generateText (GPT-4o)
    participant Tools as Tools (calculator, tasks)
    participant Storage as InMemoryStorage

    main->>SimpleAgent: start
    SimpleAgent->>Traceloop: withWorkflow(session metadata)
    Traceloop->>LLM: generateText(prompt, tools)
    LLM->>Tools: execute calculate/add
    Tools->>Storage: log calculation
    Storage-->>Tools: result
    Tools-->>LLM: calculation result
    LLM->>Tools: execute createTask
    Tools->>Storage: create task
    Storage-->>Tools: task id
    LLM-->>Traceloop: final response
    Traceloop-->>SimpleAgent: response
    SimpleAgent-->>main: done (report stats)
Loading
sequenceDiagram
    autonumber
    participant Span
    participant transformAiSdk as transformAiSdkSpanAttributes
    participant transformLLM as transformLLMSpans
    participant transformTelemetry as transformTelemetryMetadata
    participant Output

    Span->>transformAiSdk: span(name, attrs)
    transformAiSdk->>transformLLM: transformLLMSpans(attrs, span.name)
    transformLLM->>transformTelemetry: transformTelemetryMetadata(attrs, span.name)
    alt ai.telemetry.metadata.agent present
        transformTelemetry->>Output: set GEN_AI_AGENT_NAME
        alt root AI span (run.ai)
            transformTelemetry->>Output: set TRACELOOP_SPAN_KIND = "agent" & TRACELOOP_ENTITY_NAME
        end
    end
    alt ai.toolCall present
        transformLLM->>Output: set TRACELOOP_SPAN_KIND = "tool", TRACELOOP_ENTITY_NAME from tool, set TRACELOOP_ENTITY_INPUT/OUTPUT, remove ai.toolCall.args/result
    end
    transformLLM-->>transformAiSdk: enhanced attrs
    transformAiSdk-->>Span: apply attrs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing extra attention:
    • Memory semantics, eviction and concurrency in packages/sample-app/src/sample_vercel_ai_agent.ts.
    • zod schemas, input validation, and error paths in packages/sample-app/src/sample_vercel_ai_agent_simple.ts.
    • Correct root-span detection and consistent span.name propagation in packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts.
    • Lifecycle, TTL, capacity and cleanup logic for the trace-scoped agent-name cache in packages/traceloop-sdk/src/lib/tracing/span-processor.ts.
    • Test expectations and recording fidelity in the new tests/recording files.

Possibly related PRs

Suggested reviewers

  • galkleinman
  • avivhalfon

"I hop through traces with tiny feet,
name agents, call tools, store memories sweet,
span kinds wear labels and tests give a clap,
scripts run agents — then I nap on a map 🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding agent detection support for AI SDK, which aligns with the core objective of auto-detecting agent metadata from Vercel AI SDK telemetry.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-ai-sdk-agent-detection

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed everything up to e4790d0 in 2 minutes and 7 seconds. Click for details.
  • Reviewed 671 lines of code in 5 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:368
  • Draft comment:
    The variable metadataAttributes is populated but never used later. Consider removing it unless you plan to use it in future enhancements.
  • Reason this comment was not posted:
    Comment was on unchanged code.
2. packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:398
  • Draft comment:
    Good integration for agent detection. As an optional improvement, consider handling empty or whitespace-only 'agent' values (e.g., trim the value before setting agent attributes).
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 15% vs. threshold = 50% This comment is phrased as "As an optional improvement, consider..." which is a soft suggestion rather than identifying a clear bug or issue. The rules state that comments should not be speculative and should clearly require a code change. This is explicitly marked as "optional" by the commenter. While handling empty/whitespace values could be a valid improvement, the comment doesn't demonstrate that this is actually a problem in practice - it's just a "nice to have" suggestion. The code change is adding new functionality for agent detection, and the comment is suggesting additional validation that wasn't part of the original change scope. The comment could be valid if empty or whitespace-only agent names would cause actual problems downstream. Without seeing how GEN_AI_AGENT_NAME is used elsewhere, I can't be certain this isn't a real issue. Maybe empty agent names break something? Even if empty agent names could theoretically cause issues, the comment is explicitly framed as "optional" and uses "consider" language, which violates the rule about making clear, actionable comments. If this were a real issue, it should be stated definitively. The burden of proof is on keeping the comment, and "optional improvement" suggestions should be deleted. This comment should be deleted. It's explicitly marked as "optional" and uses tentative language ("consider"), which doesn't meet the bar for actionable review comments. The rules state comments should clearly require a code change, not suggest optional improvements.
3. packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:405
  • Draft comment:
    The comment about context propagation is helpful. Ensure that users are aware that metadata should be set in context before span creation if child spans need to inherit it.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is asking the PR author to ensure that users are aware of a specific behavior, which is not allowed according to the rules. It doesn't provide a specific code suggestion or ask for a test to be written. It seems to be more of a reminder or a guideline rather than a specific actionable comment.

Workflow ID: wflow_6cpovWRRyfEGSkwq

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Updated agent detection to only set `traceloop.span.kind: "agent"` on the
root AI span (ai.generateText / run.ai), not on child spans like
text.generate or tool calls.

Changes:
- Pass span name through transformation chain
- Only set span kind when span name is "ai.generateText"
- Still set `gen_ai.agent.name` on all spans for context
- Added test to verify child spans don't get marked as agent

All 6 agent tests passing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (1)

1749-1824: Agent metadata tests align well with new transformLLMSpans behavior

The three new tests correctly exercise:

  • Root span behavior: ai.generateText sets GEN_AI_AGENT_NAME, TRACELOOP_SPAN_KIND = "agent", and association properties.
  • Child span behavior: ai.generateText.doGenerate sets GEN_AI_AGENT_NAME but not TRACELOOP_SPAN_KIND.
  • No-agent behavior: neither agent attribute nor span kind is set.

This gives clear coverage of the new agent-handling branches without over-specifying unrelated metadata behavior.

You might optionally add an assertion that ai.telemetry.metadata.agent is removed in the root-span test to mirror earlier metadata-removal expectations, but current coverage is already solid.

packages/sample-app/src/sample_vercel_ai_agent.ts (1)

222-229: Conversation turn calculation is slightly off inside the system prompt/metadata

You use this.conversationHistory.length / 2 + 1 both for logging and in the system prompt/metadata. Before adding the current user message this yields an integer (correct turn), but after pushing the user message it becomes fractional (e.g., 1.5) for the same turn in the system prompt and experimental_telemetry.metadata.conversationTurn.

To keep turn numbers consistent and integer, consider normalizing the expression, e.g.:

-        console.log(
-          `📋 Session: ${this.sessionId} | User: ${
-            this.userId || "anonymous"
-          } | Turn: ${this.conversationHistory.length / 2 + 1}\n`,
-        );
+        const turn =
+          Math.floor(this.conversationHistory.length / 2) + 1;
+        console.log(
+          `📋 Session: ${this.sessionId} | User: ${
+            this.userId || "anonymous"
+          } | Turn: ${turn}\n`,
+        );
@@
-Conversation Turn: ${this.conversationHistory.length / 2 + 1}`,
+Conversation Turn: ${turn}`,
@@
-              conversationTurn: this.conversationHistory.length / 2 + 1,
+              conversationTurn: turn,

Also applies to: 255-257, 273-278

packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)

367-410: Agent metadata handling looks correct; confirm interaction with span renaming order

The new agent handling in transformTelemetryMetadata and the plumbed spanName argument in transformLLMSpans/transformAiSdkSpanAttributes look logically sound:

  • ai.telemetry.metadata.agent is promoted to:
    • SpanAttributes.GEN_AI_AGENT_NAME on all spans for context.
    • SpanAttributes.TRACELOOP_SPAN_KIND = "agent" only when spanName === AI_GENERATE_TEXT (root span).
  • Association properties continue to be set for all metadata keys and original ai.telemetry.metadata.* keys are still removed, preserving previous behavior.

One subtle point to verify: TRACELOOP_SPAN_KIND is gated on spanName === AI_GENERATE_TEXT, but spans may be renamed by transformAiSdkSpanNames (ai.generateTextrun.ai). This logic assumes that attribute transformation runs while the span name is still the raw AI SDK name.

If there’s any chance transformAiSdkSpanNames runs before transformAiSdkSpanAttributes, you may want to:

  • Either ensure ordering (attributes first, then names), or
  • Broaden the check to also recognize the renamed root span, e.g. by comparing against HANDLED_SPAN_NAMES[AI_GENERATE_TEXT] as well.

Please confirm the actual order in which transformAiSdkSpanNames and transformAiSdkSpanAttributes are invoked in your OTEL pipeline so root spans reliably get traceloop.span.kind = "agent".

Also applies to: 421-435, 468-469

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d6ebc23 and 10fbdbb.

📒 Files selected for processing (5)
  • packages/sample-app/package.json (1 hunks)
  • packages/sample-app/src/sample_vercel_ai_agent.ts (1 hunks)
  • packages/sample-app/src/sample_vercel_ai_agent_simple.ts (1 hunks)
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (6 hunks)
  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
packages/*/package.json

📄 CodeRabbit inference engine (CLAUDE.md)

Use workspace:* for intra-repo package dependencies in package.json

Files:

  • packages/sample-app/package.json
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/sample-app/src/sample_vercel_ai_agent.ts
  • packages/sample-app/src/sample_vercel_ai_agent_simple.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/sample-app/src/sample_vercel_ai_agent.ts
  • packages/sample-app/src/sample_vercel_ai_agent_simple.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/ai-semantic-conventions/src/SemanticAttributes.ts : Define all AI/LLM span attribute constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
🧬 Code graph analysis (4)
packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (2)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)
  • transformLLMSpans (421-435)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
packages/sample-app/src/sample_vercel_ai_agent.ts (2)
packages/traceloop-sdk/src/lib/tracing/decorators.ts (2)
  • tool (290-296)
  • agent (282-288)
packages/traceloop-sdk/src/lib/client/dataset/row.ts (1)
  • data (26-28)
packages/sample-app/src/sample_vercel_ai_agent_simple.ts (2)
packages/traceloop-sdk/src/lib/tracing/decorators.ts (2)
  • tool (290-296)
  • task (274-280)
packages/traceloop-sdk/src/lib/client/experiment/experiment.ts (1)
  • createTask (168-194)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
🔇 Additional comments (1)
packages/sample-app/package.json (1)

23-24: New Vercel agent scripts are consistent with existing patterns

The two new scripts follow the established npm run build && node dist/... convention and correctly point to the new agent entrypoints. No issues from a tooling or consistency standpoint.

Comment on lines +102 to +106
async function runSimpleAgent() {
// Generate session metadata for tracking
const sessionId = `simple_session_${Date.now()}_${crypto.randomUUID().substring(0, 8)}`;
const userId = "demo_user_simple";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Import randomUUID instead of relying on global crypto

sessionId is built with crypto.randomUUID(), but crypto is not imported. As with the other agent sample, this may throw ReferenceError: crypto is not defined on Node runtimes where Web Crypto is not exposed as a global, despite "node": ">=14" in package.json.

Safer pattern:

-import * as traceloop from "@traceloop/node-server-sdk";
+import * as traceloop from "@traceloop/node-server-sdk";
+import { randomUUID } from "crypto";
@@
-  const sessionId = `simple_session_${Date.now()}_${crypto.randomUUID().substring(
-    0,
-    8,
-  )}`;
+  const sessionId = `simple_session_${Date.now()}_${randomUUID().substring(
+    0,
+    8,
+  )}`;

Please verify this against the Node versions you expect contributors to use when running the sample app.



---

🏁 Script executed:

```shell
#!/bin/bash
# Check if crypto is imported in the sample file
echo "=== Checking imports in sample_vercel_ai_agent_simple.ts ==="
head -30 packages/sample-app/src/sample_vercel_ai_agent_simple.ts

echo -e "\n=== Checking for crypto references ==="
rg -n "crypto\|randomUUID" packages/sample-app/src/sample_vercel_ai_agent_simple.ts -A2 -B2

echo -e "\n=== Checking package.json Node version ==="
cat packages/sample-app/package.json | jq '.engines.node, .node'

Length of output: 1023


🌐 Web query:

When did Node.js crypto.randomUUID become available as global?

💡 Result:

crypto.randomUUID became available on the global crypto (globalThis.crypto.randomUUID) in Node.js v16.7.0 (implementation landed in the v16.7.0 release). [1][2]

Sources:

  • Node.js Web Crypto docs (shows crypto.randomUUID added in v16.7.0). [1]
  • Node.js v16.7.0 release notes (commit: "implement webcrypto.randomUUID"). [2]

🏁 Script executed:

#!/bin/bash
# Check what's actually at lines 102-106
echo "=== Lines 102-106 of sample_vercel_ai_agent_simple.ts ==="
sed -n '102,106p' packages/sample-app/src/sample_vercel_ai_agent_simple.ts

echo -e "\n=== Context: lines 95-115 ==="
sed -n '95,115p' packages/sample-app/src/sample_vercel_ai_agent_simple.ts

Length of output: 915


Import randomUUID instead of relying on global crypto

crypto.randomUUID became available on the global crypto (globalThis.crypto.randomUUID) in Node.js v16.7.0, but the package.json specifies ">=14". Code at line 104 uses crypto.randomUUID() without importing it, which will throw ReferenceError: crypto is not defined on Node 14 and 15.

Safer pattern:

import * as traceloop from "@traceloop/node-server-sdk";
+import { randomUUID } from "crypto";
import { openai } from "@ai-sdk/openai";

Then at line 104:

-  const sessionId = `simple_session_${Date.now()}_${crypto.randomUUID().substring(0, 8)}`;
+  const sessionId = `simple_session_${Date.now()}_${randomUUID().substring(0, 8)}`;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/sample-app/src/sample_vercel_ai_agent_simple.ts around lines 102 to
106, the code calls crypto.randomUUID() but package.json allows Node >=14 where
globalThis.crypto may be undefined; import the function explicitly (e.g., import
{ randomUUID } from "crypto") at the top of the file and replace
crypto.randomUUID() with randomUUID() (or call randomUUID().substring(0,8) as
before) so the code works on Node 14/15.

Comment on lines +216 to +220
constructor(userId?: string) {
this.sessionId = `session_${Date.now()}_${crypto.randomUUID().substring(0, 8)}`;
this.userId = userId;
console.log(`🆔 Initialized agent with session: ${this.sessionId}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Avoid relying on global crypto.randomUUID for Node compatibility

crypto.randomUUID() is used without importing crypto. On many Node versions (especially earlier ones still covered by "node": ">=14" in package.json), crypto is not a global, which would cause a ReferenceError at runtime.

Consider importing from the Node crypto module instead:

-import * as traceloop from "@traceloop/node-server-sdk";
+import * as traceloop from "@traceloop/node-server-sdk";
+import { randomUUID } from "crypto";
@@
-  constructor(userId?: string) {
-    this.sessionId = `session_${Date.now()}_${crypto.randomUUID().substring(
-      0,
-      8,
-    )}`;
+  constructor(userId?: string) {
+    this.sessionId = `session_${Date.now()}_${randomUUID().substring(0, 8)}`;

This keeps the sample working across a wider range of Node runtimes.

Please double-check your targeted Node versions and ensure this import pattern matches your tsconfig/module setup.




🏁 Script executed:

#!/bin/bash
# Check the actual state of sample_vercel_ai_agent.ts file
find . -name "sample_vercel_ai_agent.ts" -type f 2>/dev/null | head -5

Length of output: 51


🏁 Script executed:

#!/bin/bash
# Check imports and crypto usage in the file
cat packages/sample-app/src/sample_vercel_ai_agent.ts | head -50

Length of output: 1195


🏁 Script executed:

#!/bin/bash
# Check package.json for Node version requirement
cat package.json | grep -A 2 '"engines"' 

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any crypto imports in the entire file
grep -n "crypto\|randomUUID" packages/sample-app/src/sample_vercel_ai_agent.ts

Length of output: 88


🏁 Script executed:

#!/bin/bash
# Check the full constructor context
sed -n '210,230p' packages/sample-app/src/sample_vercel_ai_agent.ts

Length of output: 754


🌐 Web query:

Node.js crypto.randomUUID() global availability which versions

💡 Result:

  • crypto.randomUUID() (on the crypto module): added in Node.js v14.17.0 (also in v15.6.0). [1][2]

  • globalThis.crypto (Web Crypto) — which exposes crypto.randomUUID as a global: added in v16.15.0 / v17.6.0 (experimental earlier), became unflagged in v19.0.0 and marked non‑experimental later. [3][4]

Sources:
[1] Node.js v14 docs — crypto.randomUUID (Added in: v14.17.0).
[2] Node.js v18/v20 docs — crypto.randomUUID (Added in: v15.6.0, v14.17.0).
[3] Node.js globals docs — crypto global added in v16.15.0 / v17.6.0.
[4] Node.js globals docs — global Web Crypto unflagged in v19.0.0.


🏁 Script executed:

#!/bin/bash
# Check sample-app package.json for Node version requirement
cat packages/sample-app/package.json | grep -A 5 '"engines"' 

Length of output: 127


🏁 Script executed:

#!/bin/bash
# Alternative: search for engine or node version anywhere in sample-app package.json
cat packages/sample-app/package.json | head -20

Length of output: 1197



Import randomUUID from Node's crypto module

The code at line 217 uses crypto.randomUUID() without importing crypto. The global crypto object is only available starting Node v16.15.0/v17.6.0, but the package targets "node": ">=14", which includes versions where this global doesn't exist and would cause a ReferenceError.

Import randomUUID from the crypto module instead, which is available in Node v14.17.0+:

import * as traceloop from "@traceloop/node-server-sdk";
+import { randomUUID } from "crypto";
import { openai } from "@ai-sdk/openai";
-    this.sessionId = `session_${Date.now()}_${crypto.randomUUID().substring(0, 8)}`;
+    this.sessionId = `session_${Date.now()}_${randomUUID().substring(0, 8)}`;

This ensures the sample works across the declared Node version range.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/sample-app/src/sample_vercel_ai_agent.ts around lines 216 to 220,
the constructor calls crypto.randomUUID() without importing crypto which can
break on Node <16 where global crypto may be undefined; import the randomUUID
function from Node's 'crypto' module at the top of the file (e.g. import {
randomUUID } from 'crypto') and replace crypto.randomUUID() with randomUUID() so
the code works across the declared Node >=14 range.

The span name transformation happens before attribute transformation in the
processing pipeline. This fix ensures we check for the transformed span name
"run.ai" instead of the original "ai.generateText" when determining if we
should set traceloop.span.kind to "agent".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@nirga nirga force-pushed the fix-ai-sdk-agent-detection branch from b396451 to 258c731 Compare November 23, 2025 14:37
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)

401-411: Consider defining span kind values as constants.

The implementation correctly uses SpanAttributes.TRACELOOP_SPAN_KIND for the attribute key, but the value "agent" on line 409 is hardcoded. For consistency with the codebase pattern of importing constants from @traceloop/ai-semantic-conventions, consider defining span kind values (e.g., SPAN_KIND_AGENT, SPAN_KIND_WORKFLOW, SPAN_KIND_TASK) as constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts.

Based on learnings, attribute constants should be imported from @traceloop/ai-semantic-conventions rather than hardcoded.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b396451 and 258c731.

📒 Files selected for processing (2)
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (6 hunks)
  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/ai-semantic-conventions/src/SemanticAttributes.ts : Define all AI/LLM span attribute constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-transformations.test.ts
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
🧬 Code graph analysis (2)
packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (2)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)
  • transformLLMSpans (422-436)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
🔇 Additional comments (5)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (2)

422-436: LGTM!

The parameter threading is clean and correctly propagates the span name for agent detection logic.


469-469: LGTM!

Correctly passes the span name to enable agent detection based on span hierarchy.

packages/traceloop-sdk/test/ai-sdk-transformations.test.ts (3)

1749-1782: LGTM!

Comprehensive test coverage for agent detection on root spans. The test correctly validates that both gen_ai.agent.name and traceloop.span.kind are set, while ensuring association properties are preserved.


1784-1806: LGTM!

Excellent test case validating the distinction between root and child span behavior. Correctly verifies that agent name propagates while span kind remains unset on child spans.


1808-1826: LGTM!

Important negative test case ensuring no false positives. Correctly validates that agent-related attributes are not set when agent metadata is absent.

Use the TraceloopSpanKindValues.AGENT enum constant instead of the string
literal "agent" for consistency with the rest of the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (2)

370-377: Agent detection and root-span handling look correct; consider decoupling from raw span name

The new spanName? parameter and agentName handling correctly:

  • Detect ai.telemetry.metadata.agent.
  • Set SpanAttributes.GEN_AI_AGENT_NAME on all spans with that metadata.
  • Set TRACELOOP_SPAN_KIND = TraceloopSpanKindValues.AGENT only when spanName === HANDLED_SPAN_NAMES[AI_GENERATE_TEXT] ("run.ai"), matching the intent to mark only the root AI span as an agent span.

One minor maintainability concern: root-span detection is now implicitly tied to the transformed span name string. If naming conventions change in the future, this logic must be kept in sync with HANDLED_SPAN_NAMES and the place where names are transformed.

A small refactor to consider (optional):

  • Introduce a helper like isRootAiRunSpan(spanName: string | undefined): boolean (co-located with HANDLED_SPAN_NAMES) and call it here, so renames only need to be updated in one place.

This keeps behavior identical while making the coupling more explicit.

Also applies to: 391-415


426-440: Span name plumb-through for agent detection is sound; watch call-order assumptions

Passing spanName? through transformLLMSpans into transformTelemetryMetadata, and then calling transformLLMSpans(span.attributes, span.name) from transformAiSdkSpanAttributes, is a clean way to give metadata transformations access to the final span name.

The only implicit assumption is that transformAiSdkSpanNames (which rewrites names to "run.ai", "text.generate", etc.) runs before transformAiSdkSpanAttributes, so the span.name seen here is already transformed. Tests likely cover this, but it’s worth keeping in mind for any future reordering of processors.

If these two always need to be used together in a specific order, an optional follow-up would be to:

  • Add a brief comment at the call site where both transformers are wired, or
  • Wrap them in a small helper that enforces order, rather than relying on convention.

Functionally, the current change looks correct and backward-compatible since spanName is optional.

Also applies to: 473-473

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 258c731 and 97ed5f4.

📒 Files selected for processing (1)
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/ai-semantic-conventions/src/SemanticAttributes.ts : Define all AI/LLM span attribute constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
📚 Learning: 2025-08-12T13:57:05.901Z
Learnt from: galzilber
Repo: traceloop/openllmetry-js PR: 643
File: packages/traceloop-sdk/test/datasets-final.test.ts:97-105
Timestamp: 2025-08-12T13:57:05.901Z
Learning: The traceloop-sdk uses a response transformer (`transformApiResponse` in `packages/traceloop-sdk/src/lib/utils/response-transformer.ts`) that converts snake_case API responses to camelCase for SDK interfaces. Raw API responses use snake_case but SDK consumers see camelCase fields.

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts
🧬 Code graph analysis (1)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
🔇 Additional comments (1)
packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts (1)

2-5: Good: using semantic-convention enum for span kind instead of string literals

Importing TraceloopSpanKindValues from @traceloop/ai-semantic-conventions keeps span-kind values centralized and avoids hardcoded strings, consistent with the semantic-conventions guideline. No issues here.

nirga and others added 2 commits November 23, 2025 16:45
When tool calls are executed in AI SDK, set the traceloop.span.kind
attribute to "tool" to properly classify these spans in the tracing
hierarchy. This ensures consistent span categorization across the SDK.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Set traceloop.entity.name attribute for better span identification:
- Agent spans: entity name set to agent name from metadata
- Tool call spans: entity name set to tool name from ai.toolCall.name

This provides consistent entity naming across all span types and improves
trace visualization and analysis.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed 1e25666 in 54 seconds. Click for details.
  • Reviewed 70 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:411
  • Draft comment:
    Agent detection now sets TRACELOOP_ENTITY_NAME using the detected agent name on root spans. Ensure that agentName is non-empty/truthy as expected.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the author to ensure that agentName is non-empty/truthy, which violates the rule against asking the author to ensure behavior. It doesn't provide a specific suggestion or point out a specific issue with the code.
2. packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:457
  • Draft comment:
    Tool call transformation now sets TRACELOOP_ENTITY_NAME from 'ai.toolCall.name', ensuring consistency for tool spans.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, describing what the code change does without suggesting any improvements or asking for clarifications. It doesn't provide any actionable feedback or raise any concerns about the code.
3. packages/traceloop-sdk/test/ai-sdk-transformations.test.ts:1750
  • Draft comment:
    The new tests for agent detection are comprehensive. Consider adding an edge case for an empty agent string to further validate behavior.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.

Workflow ID: wflow_LHWXjybnniT9vKfc

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

AI SDK only sets telemetry metadata on the root generateText span, not on
child tool call spans. This adds trace-level agent name storage and
propagation to ensure all spans in an agent trace (including tool calls)
have the gen_ai.agent.name attribute.

Implementation:
- Store agent names in a Map keyed by trace ID
- When a span has agent name, store it for the trace
- When a span doesn't have agent name but its trace does, propagate it
- Clean up old traces (keep last 1000) to prevent memory leaks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed a2d51e6 in 1 minute and 49 seconds. Click for details.
  • Reviewed 42 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 1 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:27
  • Draft comment:
    Global Map 'traceAgentNames' is used for agent name propagation across spans. This approach may cause memory retention issues in long-running processes. Consider using an LRU cache or WeakMap for better cleanup and potential concurrency safety.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 35% vs. threshold = 50% The comment is definitely about a change in the diff - the Map was added in this PR. The code does implement a basic cleanup mechanism (keeping only 1000 traces), which shows the author was aware of memory concerns. The comment suggests alternatives (LRU cache or WeakMap) but doesn't provide strong evidence that the current approach is problematic. WeakMap wouldn't work here since trace IDs are strings (primitives), not objects. An LRU cache might be better than the current FIFO approach, but the current implementation seems reasonable for the use case. The comment is somewhat speculative ("may cause memory retention issues") rather than pointing to a definite problem. The author already implemented cleanup logic, so they considered this concern. The comment does raise a valid architectural concern about using a global Map in a long-running process. The suggestion for an LRU cache is reasonable and actionable. The current FIFO cleanup (deleting the first key) is less optimal than LRU for this use case. This could be considered a code quality improvement suggestion, which the rules say are good if actionable and clear. While the comment is actionable, it's somewhat speculative ("may cause") and the author already implemented cleanup logic showing awareness of memory concerns. The WeakMap suggestion is incorrect (can't use strings as keys), which undermines the comment's credibility. The LRU cache suggestion is valid but not critical - the current approach with a 1000-entry limit is reasonable for most use cases. This feels more like a "nice to have" optimization rather than a clear issue. The comment makes a reasonable suggestion about using an LRU cache, but it's speculative and the author already implemented cleanup logic. The WeakMap suggestion is technically incorrect. Given the rule to only keep comments with STRONG EVIDENCE of correctness, and that this is more of an optimization suggestion than a clear problem, I should lean toward deleting it.

Workflow ID: wflow_9uaaDMOYqTZwlJTb

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed fc09b89 in 1 minute and 16 seconds. Click for details.
  • Reviewed 42 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:24
  • Draft comment:
    Removed 'traceAgentNames' Map which was used for propagating the agent name. Ensure that the new agent detection via transformAiSdkSpanAttributes fully handles agent metadata propagation across child spans.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is suggesting to ensure that a new method fully handles a specific functionality after a removal of a map. It is asking for confirmation of the new method's capability, which is not allowed by the rules.
2. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:237
  • Draft comment:
    Removed manual agent propagation logic in onSpanEnd. Confirm that transformAiSdkSpanAttributes now correctly assigns the agent attribute to spans, including child spans without an explicit agent name.
  • Reason this comment was not posted:
    Comment was on unchanged code.

Workflow ID: wflow_wzN0uium1bgJKOQ4

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Changes requested ❌

Reviewed 2449e59 in 2 minutes and 10 seconds. Click for details.
  • Reviewed 42 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:249
  • Draft comment:
    Review the cleanup logic: capping at 1000 entries via removing the first key may be suboptimal; consider a more predictable eviction mechanism.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 20% vs. threshold = 50% The comment is about changed code (the agent name propagation logic is new). However, the comment is somewhat vague - it says the approach "may be suboptimal" and suggests "a more predictable eviction mechanism" without being specific about what's wrong or what should be done instead. The current approach (removing the first key) is actually a reasonable FIFO approach for a Map in JavaScript, since Maps maintain insertion order. The comment doesn't explain why this is problematic or what specific alternative should be used (LRU cache? Different threshold? Different data structure?). This feels like a code quality suggestion that's not actionable enough - it's speculative ("may be suboptimal") rather than definitive, and doesn't provide clear guidance on what to change. The cleanup logic could genuinely be improved - for instance, an LRU cache would be better if traces are accessed multiple times, or batch deletion might be more efficient than deleting one entry at a time. The comment might be pointing to a legitimate concern about memory management in a production system. While there might be better approaches, the comment doesn't provide specific, actionable guidance. It uses hedging language ("may be suboptimal") and vague suggestions ("more predictable eviction mechanism"). The current approach is actually predictable (FIFO based on Map insertion order) and functional. Without concrete evidence of a problem or a specific alternative, this is more of a speculative code quality comment that isn't actionable enough to be useful. The comment is too vague and speculative to be actionable. It doesn't explain what's wrong with the current approach or provide specific alternatives. The current FIFO approach using Map's insertion order is actually predictable and reasonable for this use case.
2. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:257
  • Draft comment:
    The non-null assertion (traceAgentNames.get(traceId)!) is safe due to the preceding check, but consider refactoring for clarity.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.

Workflow ID: wflow_ImStAsbz2JZzSbZb

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

type AllInstrumentationLibraries = typeof ALL_INSTRUMENTATION_LIBRARIES;

// Store agent names per trace for propagation to child spans (tool calls)
const traceAgentNames = new Map<string, string>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider a more robust eviction strategy (e.g. LRU/timed eviction) for traceAgentNames to prevent memory buildup.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/traceloop-sdk/src/lib/tracing/span-processor.ts (2)

249-254: Inadequate cleanup removes only one entry.

The cleanup logic removes only one entry when traceAgentNames.size exceeds 1000. If multiple spans are processed in quick succession, the Map size can grow beyond the threshold.

Apply this diff to remove excess entries until the size is within bounds:

      // Clean up old traces (keep only last 1000 traces)
-      if (traceAgentNames.size > 1000) {
+      while (traceAgentNames.size > 1000) {
        const firstKey = traceAgentNames.keys().next().value;
        if (firstKey) {
          traceAgentNames.delete(firstKey);
        }
      }

27-28: Consider trace completion cleanup and bounded growth.

The module-scoped Map lacks a mechanism to detect when traces complete, so entries accumulate until the 1000-entry threshold is reached. Additionally, the cleanup at lines 249-254 removes only one entry per insertion when the limit is exceeded, meaning the Map can still grow beyond 1000 if multiple spans are processed rapidly.

Consider:

  1. Implementing a while-loop in the cleanup logic to ensure size stays within bounds
  2. Adding a TTL mechanism or event-based cleanup when traces complete to prevent stale entries from consuming memory
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fc09b89 and 2449e59.

📒 Files selected for processing (1)
  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/ai-semantic-conventions/src/SemanticAttributes.ts : Define all AI/LLM span attribute constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/src/lib/node-server-sdk.ts : Register new instrumentation packages during SDK initialization

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
🧬 Code graph analysis (1)
packages/traceloop-sdk/src/lib/tracing/span-processor.ts (1)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and test

Comment on lines 257 to 258
span.attributes[SpanAttributes.GEN_AI_AGENT_NAME] =
traceAgentNames.get(traceId)!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that direct mutation of ReadableSpan.attributes is safe.

The code directly mutates span.attributes after the span has ended. The ReadableSpan interface suggests immutability, and this pattern may cause issues with certain span implementations or exporters that expect attributes to remain unchanged post-collection.

Run the following script to check if other parts of the codebase mutate ReadableSpan attributes similarly:


🏁 Script executed:

#!/bin/bash
# Description: Search for other instances of ReadableSpan attribute mutations to verify this pattern

# Search for direct assignments to span.attributes after onEnd
rg -n -A3 -B3 'span\.attributes\[.*\]\s*=' --type=ts

Length of output: 6217


🏁 Script executed:

#!/bin/bash
# Get context around the span-processor.ts mutation (lines 240-270)
echo "=== span-processor.ts context ==="
sed -n '240,270p' packages/traceloop-sdk/src/lib/tracing/span-processor.ts

echo ""
echo "=== ai-sdk-transformations.ts context ==="
sed -n '430,465p' packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts

echo ""
echo "=== Method signature for span-processor.ts onEnd ==="
grep -n "onEnd" packages/traceloop-sdk/src/lib/tracing/span-processor.ts | head -5

Length of output: 2549


🏁 Script executed:

#!/bin/bash
# Find where transformToolCalls is called
echo "=== transformToolCalls usage ==="
rg -n "transformToolCalls" packages/traceloop-sdk/src/lib/tracing/

echo ""
echo "=== Full onSpanEnd method definition ==="
sed -n '107,275p' packages/traceloop-sdk/src/lib/tracing/span-processor.ts

echo ""
echo "=== Check for ReadableSpan type definition in codebase ==="
rg -n "ReadableSpan" packages/traceloop-sdk/src/lib/tracing/span-processor.ts | head -3

Length of output: 5183


🏁 Script executed:

#!/bin/bash
# Find transformAiSdkSpanAttributes implementation
echo "=== transformAiSdkSpanAttributes implementation ==="
rg -n "const transformAiSdkSpanAttributes" packages/traceloop-sdk/src/lib/tracing/ -A 5

echo ""
echo "=== Tests for agent name propagation ==="
rg -n "traceAgentNames\|GEN_AI_AGENT_NAME" packages/traceloop-sdk/test/ -B 2 -A 2

echo ""
echo "=== Check imports in span-processor.ts ==="
head -20 packages/traceloop-sdk/src/lib/tracing/span-processor.ts

Length of output: 1327


🌐 Web query:

OpenTelemetry ReadableSpan attributes mutability - is it safe to mutate span.attributes in onEnd callback

💡 Result:

Short answer: No — do not mutate span.attributes in onEnd. The OpenTelemetry spec requires that the span passed to OnEnd is a readable (ended) span and must not be modified; if you need to change attributes at end-time do it in the OnEnding/OnEnding (or the span processor callback invoked while the span is still mutable) or earlier (onStart / via a ReadWriteSpan). [1][2]

Sources:

  • OpenTelemetry tracing SDK spec — OnEnding (span still mutable) and OnEnd (ended/read-only). [1]
  • Language SDK docs showing ReadWriteSpan/onEnd usage guidance. [2]

Fix mutations of ReadableSpan.attributes — direct modification in onEnd violates OpenTelemetry specification.

The code mutates span.attributes in the onEnd callback, which violates the OpenTelemetry specification. The span passed to onEnd is an ended/read-only span and must not be modified; attribute changes must happen during onEnding (while span is still mutable) or onStart.

Move mutations to an earlier lifecycle stage:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts:257–258 — Agent name propagation should use onStart or store data before span ends
  • packages/traceloop-sdk/src/lib/tracing/ai-sdk-transformations.ts:448–460 — transformToolCalls and related mutations should be applied before span collection completes, not in onEnd

nirga and others added 2 commits November 24, 2025 11:16
Added comprehensive integration test using Polly.js recording to verify:
- Root span gets agent name, span kind, and entity name from metadata
- Tool call spans inherit agent name from parent and get tool span kind
- Child LLM spans inherit agent name but don't get span kind

Using trace-level agent name storage for now (will be improved later).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive integration test using Polly.js to verify:
- Root span (run.ai) receives agent attributes from metadata
- Agent name propagates to tool call spans
- Tool spans receive proper span kind and entity name
- Child LLM spans inherit agent name but not span kind

Also adds zod as dev dependency for AI SDK tool schema definitions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed e49e8ad in 1 minute and 56 seconds. Click for details.
  • Reviewed 238 lines of code in 3 files
  • Skipped 1 files when reviewing.
  • Skipped posting 5 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/package.json:117
  • Draft comment:
    Verify if 'zod' is needed as a runtime dependency. If it's only used in tests or non‐runtime code, consider moving it to devDependencies.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
2. packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts:39
  • Draft comment:
    Added a 30s timeout for the test suite. Ensure this duration is appropriate for external calls and avoids flakiness.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to ensure that the 30s timeout is appropriate, which violates the rule against asking the author to confirm or ensure things. It doesn't provide a specific suggestion or point out a clear issue with the code.
3. packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts:86
  • Draft comment:
    Updated the tool definition to use 'inputSchema' (with descriptive fields) instead of 'parameters'. This improves clarity and aligns with the new API.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, explaining a change that was made without suggesting any action or asking for clarification. It doesn't provide any actionable feedback or raise any concerns about the code.
4. packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts:105
  • Draft comment:
    The execute function now returns full input details (operation, a, b) along with result. Confirm downstream consumers can handle this updated structure.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
5. packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts:149
  • Draft comment:
    The assertion for 'result.text' has been removed. Ensure that this change is intentional and that consumers no longer expect a 'text' property in the response.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.

Workflow ID: wflow_jREr53N8fCMeQtny

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2449e59 and e49e8ad.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/traceloop-sdk/package.json (1 hunks)
  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har (1 hunks)
  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har
🧰 Additional context used
📓 Path-based instructions (4)
packages/*/package.json

📄 CodeRabbit inference engine (CLAUDE.md)

Use workspace:* for intra-repo package dependencies in package.json

Files:

  • packages/traceloop-sdk/package.json
packages/traceloop-sdk/package.json

📄 CodeRabbit inference engine (CLAUDE.md)

When adding a new instrumentation package, add it to the main SDK dependencies

Files:

  • packages/traceloop-sdk/package.json
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/package.json : When adding a new instrumentation package, add it to the main SDK dependencies

Applied to files:

  • packages/traceloop-sdk/package.json
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/package.json
  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/package.json
  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/package.json
  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/src/lib/node-server-sdk.ts : Register new instrumentation packages during SDK initialization

Applied to files:

  • packages/traceloop-sdk/package.json
  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
📚 Learning: 2025-08-13T08:00:42.668Z
Learnt from: galzilber
Repo: traceloop/openllmetry-js PR: 643
File: packages/traceloop-sdk/src/lib/interfaces/dataset.interface.ts:27-27
Timestamp: 2025-08-13T08:00:42.668Z
Learning: In packages/traceloop-sdk/src/lib/interfaces/dataset.interface.ts, when the user said "there is no date" in response to a comment about removing "date" from column type unions, they may have been referring to local changes not yet reflected in the PR branch, as the code still contained "date" in the union types at lines 27 and 43.

Applied to files:

  • packages/traceloop-sdk/package.json
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Use ts-mocha as the TypeScript test runner for package tests

Applied to files:

  • packages/traceloop-sdk/package.json
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts
🧬 Code graph analysis (1)
packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts (3)
packages/traceloop-sdk/test/test-setup.ts (2)
  • getSharedExporter (37-39)
  • initializeSharedTraceloop (23-35)
packages/traceloop-sdk/src/lib/tracing/decorators.ts (1)
  • tool (290-296)
packages/ai-semantic-conventions/src/SemanticAttributes.ts (1)
  • SpanAttributes (17-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and test
🔇 Additional comments (5)
packages/traceloop-sdk/package.json (1)

120-121: Addition of zod devDependency looks good.

The addition of zod as a devDependency aligns with the PR objectives of adding agent detection unit tests and sample applications that rely on zod-based parameter schemas. The version constraint ^3.25.76 is appropriate for a dev dependency, and the placement follows standard patterns (dev-only utilities in devDependencies, internal packages using workspace:*).

packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts (4)

17-30: LGTM: Imports follow coding guidelines.

The semantic constants are correctly imported from @traceloop/ai-semantic-conventions as per the coding guidelines. The AI SDK's tool() factory import is appropriate for this integration test scenario.


32-82: LGTM: Test setup and hooks are well-structured.

The Polly configuration properly handles recording/replay modes, filters sensitive headers, and uses shared Traceloop initialization to avoid conflicts with other test suites. The cleanup in afterEach ensures proper test isolation.


84-114: LGTM: Comprehensive tool definition with proper validation.

The calculator tool is well-implemented with zod schema validation, all operations covered, and proper error handling for division by zero. Using the AI SDK's tool() factory is appropriate for this integration test.


116-153: LGTM: Proper use of workflow decorator.

The test correctly uses traceloop.withWorkflow() as per coding guidelines and properly configures telemetry metadata for agent detection testing. The span retrieval logic is straightforward.

Comment on lines +195 to +231
// Verify tool call span inherits agent name
if (toolSpan) {
assert.strictEqual(
toolSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Tool span should inherit agent name from parent",
);
assert.strictEqual(
toolSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
"tool",
"Tool span should have span kind = tool",
);
assert.ok(
toolSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
"Tool span should have entity name",
);
}

// Verify child LLM span inherits agent name
if (childLLMSpan) {
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Child LLM span should inherit agent name from parent",
);
// Child LLM span should NOT have span kind or entity name
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
undefined,
"Child LLM span should not have span kind",
);
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
undefined,
"Child LLM span should not have entity name",
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add assertions for tool and child LLM span existence.

The conditional checks for toolSpan and childLLMSpan (lines 196 and 214) mean these verifications are skipped if the spans don't exist. Given that the PR objectives explicitly mention verifying agent name propagation to tool call spans, these spans are expected to exist. The test should assert their existence to catch regressions.

Apply this diff to add the missing assertions:

     );
 
     // Verify tool call span inherits agent name
+    assert.ok(toolSpan, "Tool span should exist");
     if (toolSpan) {
       assert.strictEqual(
     }
 
     // Verify child LLM span inherits agent name
+    assert.ok(childLLMSpan, "Child LLM span should exist");
     if (childLLMSpan) {
       assert.strictEqual(
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Verify tool call span inherits agent name
if (toolSpan) {
assert.strictEqual(
toolSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Tool span should inherit agent name from parent",
);
assert.strictEqual(
toolSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
"tool",
"Tool span should have span kind = tool",
);
assert.ok(
toolSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
"Tool span should have entity name",
);
}
// Verify child LLM span inherits agent name
if (childLLMSpan) {
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Child LLM span should inherit agent name from parent",
);
// Child LLM span should NOT have span kind or entity name
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
undefined,
"Child LLM span should not have span kind",
);
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
undefined,
"Child LLM span should not have entity name",
);
}
// Verify tool call span inherits agent name
assert.ok(toolSpan, "Tool span should exist");
if (toolSpan) {
assert.strictEqual(
toolSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Tool span should inherit agent name from parent",
);
assert.strictEqual(
toolSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
"tool",
"Tool span should have span kind = tool",
);
assert.ok(
toolSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
"Tool span should have entity name",
);
}
// Verify child LLM span inherits agent name
assert.ok(childLLMSpan, "Child LLM span should exist");
if (childLLMSpan) {
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.GEN_AI_AGENT_NAME],
"test_calculator_agent",
"Child LLM span should inherit agent name from parent",
);
// Child LLM span should NOT have span kind or entity name
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_SPAN_KIND],
undefined,
"Child LLM span should not have span kind",
);
assert.strictEqual(
childLLMSpan.attributes[SpanAttributes.TRACELOOP_ENTITY_NAME],
undefined,
"Child LLM span should not have entity name",
);
}
🤖 Prompt for AI Agents
In packages/traceloop-sdk/test/ai-sdk-agent-integration.test.ts around lines 195
to 231, the test currently guards attribute checks with if (toolSpan) and if
(childLLMSpan) which silently skips checks when spans are missing; add explicit
existence assertions (e.g., assert.ok(toolSpan, "Expected toolSpan to exist")
and assert.ok(childLLMSpan, "Expected childLLMSpan to exist")) immediately
before inspecting their attributes so the test fails fast when spans are absent,
then keep the subsequent attribute assertions unchanged.

Implement hybrid cleanup for trace agent name map:
- Primary: Clean up when root span ends (detected via parentSpanContext)
- Safety net: TTL-based cleanup (5min) for orphaned entries
- Probabilistic cleanup runs every ~100 spans

This prevents memory leaks while ensuring precise cleanup timing.

Also fixes root span detection by using parentSpanContext instead of
parentSpanId, which is not always populated in exported spans.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed 3440e2c in 1 minute and 24 seconds. Click for details.
  • Reviewed 177 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 4 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har:36
  • Draft comment:
    HAR recording updated with new response IDs, header, and timing values reflecting agent instrumentation. Ensure these test updates match the expected output.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
2. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:27
  • Draft comment:
    TTL-based traceAgentNames map is a good approach for agent propagation. Consider adding unit tests for cleanupExpiredTraceAgentNames to cover edge cases.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:52
  • Draft comment:
    The isRootSpan utility correctly identifies root spans; verify that this logic covers all edge cases per OTel specifications.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
4. packages/traceloop-sdk/src/lib/tracing/span-processor.ts:275
  • Draft comment:
    Agent propagation in onSpanEnd is clear. Storing the agent name and cleaning it up (especially for root spans and via probabilistic cleanup) is a neat low-overhead design. Consider tuning the 1% cleanup probability if trace volume increases.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_EOi52ZnUZAjGcpqH

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/traceloop-sdk/src/lib/tracing/span-processor.ts (1)

271-295: CRITICAL: ReadableSpan mutation violates OpenTelemetry specification.

Lines 283-284 directly mutate span.attributes after the span has ended. As noted in previous reviews, the OpenTelemetry specification requires that spans passed to onEnd are read-only and must not be modified. Attribute modifications must occur in onStart or while the span is still mutable (ReadWriteSpan).

Required fix: Move agent name propagation to onStart or use a different approach:

Option 1: Store propagation data during onStart
Instead of modifying spans in onEnd, check the trace map during onStart and set the attribute then:

 const onSpanStart = (span: Span): void => {
+  // Propagate agent name from trace if available
+  const traceId = span.spanContext().traceId;
+  const existingAgentName = traceAgentNames.get(traceId)?.agentName;
+  if (existingAgentName) {
+    span.setAttribute(SpanAttributes.GEN_AI_AGENT_NAME, existingAgentName);
+  }
+
   const workflowName = context.active().getValue(WORKFLOW_NAME_KEY);
   // ... rest of onStart logic

Option 2: Use SpanProcessor with ReadWriteSpan
Implement a custom span processor that has access to ReadWriteSpan during processing, allowing mutations before the span is marked as ended.

Note: This issue blocks the PR and must be resolved before merge.

🧹 Nitpick comments (1)
packages/traceloop-sdk/src/lib/tracing/span-processor.ts (1)

27-35: Consider adding a size limit to prevent unbounded memory growth.

The traceAgentNames map has no maximum size limit. In high-volume production environments with many concurrent traces, this could lead to memory issues even with TTL-based cleanup. Consider adding a size threshold (e.g., 1000 entries) and an eviction strategy (LRU or FIFO) when the limit is reached.

Example approach:

 const traceAgentNames = new Map<
   string,
   { agentName: string; timestamp: number }
 >();
 
+const MAX_TRACE_AGENT_NAMES = 1000;
+
 // TTL for trace agent names (5 minutes)
 const TRACE_AGENT_NAME_TTL = 5 * 60 * 1000;

Then enforce the limit when adding entries:

// When storing agent name (in onSpanEnd)
if (traceAgentNames.size >= MAX_TRACE_AGENT_NAMES) {
  // Remove oldest entry (first in iteration order for Map)
  const firstKey = traceAgentNames.keys().next().value;
  if (firstKey) traceAgentNames.delete(firstKey);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e49e8ad and 3440e2c.

📒 Files selected for processing (2)
  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har (1 hunks)
  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Import AI/LLM semantic attribute constants from @traceloop/ai-semantic-conventions rather than hardcoding strings

Files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
packages/traceloop-sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/traceloop-sdk/**/*.{ts,tsx}: Use the provided decorators (@workflow, @task, @agent) for workflow/task/agent spans instead of re-implementing them
For manual LLM operations, use trace.withLLMSpan from @traceloop/node-server-sdk

Files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
**/recordings/**

📄 CodeRabbit inference engine (CLAUDE.md)

Store HTTP interaction recordings for tests under recordings/ directories for Polly.js replay

Files:

  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : Use the provided decorators (workflow, task, agent) for workflow/task/agent spans instead of re-implementing them

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/**/*.{ts,tsx} : For manual LLM operations, use trace.withLLMSpan from traceloop/node-server-sdk

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must create spans with appropriate AI/LLM semantic attributes for calls they wrap

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/{instrumentation-*,traceloop-sdk}/**/*.{ts,tsx} : Import AI/LLM semantic attribute constants from traceloop/ai-semantic-conventions rather than hardcoding strings

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
  • packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/ai-semantic-conventions/src/SemanticAttributes.ts : Define all AI/LLM span attribute constants in packages/ai-semantic-conventions/src/SemanticAttributes.ts

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/traceloop-sdk/src/lib/node-server-sdk.ts : Register new instrumentation packages during SDK initialization

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Do not implement anonymous telemetry collection in instrumentation packages; telemetry is collected only in the SDK

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
📚 Learning: 2025-08-24T22:08:07.023Z
Learnt from: CR
Repo: traceloop/openllmetry-js PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T22:08:07.023Z
Learning: Applies to packages/instrumentation-*/**/*.{ts,tsx} : Instrumentations must extract request/response data and token usage from wrapped calls

Applied to files:

  • packages/traceloop-sdk/src/lib/tracing/span-processor.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build and test
🔇 Additional comments (4)
packages/traceloop-sdk/recordings/Test-AI-SDK-Agent-Integration-with-Recording_2039949225/should-propagate-agent-name-to-tool-call-spans_3577231859/recording.har (2)

1-172: Recording structure and security look good.

The HAR recording structure is valid and appropriate for Polly.js test replay. No security concerns detected - no API keys or sensitive authentication data are exposed in the headers. The recording correctly captures a tool call scenario that aligns with the test name for propagating agent names to tool call spans.

Note: The agent metadata itself wouldn't appear in this OpenAI API recording, as it's handled at the AI SDK instrumentation/telemetry layer, not passed to the OpenAI API.


32-32: Recording correctly uses OpenAI's Responses API format—no changes needed.

The Responses API uses input instead of messages, and request bodies include input items with role and content fields. The Responses API is a superset of Chat Completions with additional features, so the format difference is expected. OpenAI released the Responses API in March 2025 as the successor to Chat Completions. The recording's endpoint and format are both correct for this API version.

packages/traceloop-sdk/src/lib/tracing/span-processor.ts (2)

37-47: LGTM — Cleanup logic is correct.

The TTL-based cleanup implementation correctly removes expired entries. However, note that this function's effectiveness depends entirely on how frequently it's called. The probabilistic invocation (1% per span at line 293) may be insufficient in both low-volume (rarely runs) and high-volume (accumulation between cleanups) scenarios.

Consider whether deterministic cleanup (e.g., setInterval or size-threshold-triggered) would be more reliable:

// Example: Run cleanup on a fixed interval
let cleanupInterval: NodeJS.Timeout | null = null;

export const startCleanupInterval = () => {
  if (!cleanupInterval) {
    cleanupInterval = setInterval(cleanupExpiredTraceAgentNames, 60000); // Every minute
  }
};

49-59: Root span detection logic is correct and follows OpenTelemetry standards.

The implementation correctly identifies root spans. The pattern of checking parentSpanContext.spanId === "0000000000000000" is the canonical approach used by OpenTelemetry Collector and aligns with OT specifications where root spans have an all-zero span ID. The defensive checks (!parentContext and !parentContext.spanId) provide safe guards before the ID comparison. This logic works correctly across OpenTelemetry SDK versions.

@nirga nirga merged commit a1ab720 into main Nov 24, 2025
8 checks passed
@nirga nirga deleted the fix-ai-sdk-agent-detection branch November 24, 2025 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants