Skip to content

Telemetry: Add agent detection#33675

Merged
valentinpalkovic merged 5 commits intonextfrom
valentin/implement-agent-detection-telemetry
Jan 28, 2026
Merged

Telemetry: Add agent detection#33675
valentinpalkovic merged 5 commits intonextfrom
valentin/implement-agent-detection-telemetry

Conversation

@valentinpalkovic
Copy link
Copy Markdown
Contributor

@valentinpalkovic valentinpalkovic commented Jan 27, 2026

Closes #

What I did

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Run event-collector in Storybook's monorepo (yarn jiti ./event-log-collector.ts ) (Adjust the script to log the req.body)
  2. Run STORYBOOK_TELEMETRY_URL=http://localhost:6007/event-log npx storybook init in an agent and observe that the agent is appropriately detected (e.g. claude or amp agent)

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-33675-sha-017acedc. Try it out in a new sandbox by running npx storybook@0.0.0-pr-33675-sha-017acedc sandbox or in an existing project with npx storybook@0.0.0-pr-33675-sha-017acedc upgrade.

More information
Published version 0.0.0-pr-33675-sha-017acedc
Triggered by @valentinpalkovic
Repository storybookjs/storybook
Branch valentin/implement-agent-detection-telemetry
Commit 017acedc
Datetime Tue Jan 27 15:00:27 UTC 2026 (1769526027)
Workflow run 21402149227

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=33675

Summary by CodeRabbit

  • New Features

    • Storybook now detects AI agents (Claude Code, Gemini CLI, Cursor, Codex, AMP, etc.) and adds optional agent/isAgent information to telemetry, metadata, and runtime context.
  • Tests

    • Added comprehensive tests for agent detection covering explicit signals, precedence rules, TTY vs non‑TTY heuristics, CI interactions, unknown-agent handling, and no-signal scenarios.

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

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Jan 27, 2026

View your CI Pipeline Execution ↗ for commit 0d8afbe

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ✅ Succeeded 5m 52s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-28 11:32:47 UTC

@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Jan 27, 2026

View your CI Pipeline Execution ↗ for commit 017aced

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ❌ Failed 11m 21s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-27 15:12:13 UTC

Comment thread code/core/src/telemetry/types.ts Outdated
generatedAt?: number;
userSince?: number;
/** Whether this process is likely invoked by an AI agent */
isAgent?: boolean;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Redundant to agent: { name: 'unknown' } IMO

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Jan 27, 2026

📝 Walkthrough

Walkthrough

Adds runtime AI-agent detection and telemetry integration: a new detector inspects explicit environment signals and non‑TTY heuristics to produce agent metadata; telemetry now includes that agent info; tests validate precedence, TTY/CI behavior, and heuristic fallbacks.

Changes

Cohort / File(s) Change Summary
Core Agent Detection
code/core/src/telemetry/detect-agent.ts
New module introducing types (KnownAgentName, AgentInfo, AgentDetection) and detectAgent(); detects explicit env signals (AMP, claude-code, gemini-cli, codex, cursor, AGENT) with precedence, then applies non‑TTY heuristics (TERM, GIT_PAGER) to infer unknown agents.
Agent Detection Tests
code/core/src/telemetry/detect-agent.test.ts
New Vitest suite covering explicit-signal precedence, unknown handling, TTY vs non‑TTY heuristics, CI behavior, and no-signal cases; asserts { isAgent, agent? } results.
Telemetry Integration
code/core/src/telemetry/telemetry.ts
Imports and invokes detectAgent, computes inCI, and injects agent (and isAgent in telemetry context) into global telemetry metadata alongside existing fields.
Type Definitions
code/core/src/telemetry/types.ts
Imports AgentInfo and extends StorybookMetadata with an optional agent?: AgentInfo.

Sequence Diagram(s)

mermaid
sequenceDiagram
actor CLI as CLI Process
participant Detector as detectAgent
participant Telemetry as Telemetry Module
participant Server as Telemetry Service

CLI->>Detector: provide env + stdoutIsTTY
Detector-->>CLI: returns { isAgent, agent? }
CLI->>Telemetry: build metadata (includes agent, isAgent, isTTY, platform, nodeVersion...)
Telemetry->>Server: send telemetry payload

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link
Copy Markdown
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

🤖 Fix all issues with AI agents
In `@code/core/src/telemetry/detect-agent.ts`:
- Around line 1-63: The KnownAgentName union includes 'opencode' but
detectExplicitAgent never returns it; update detectExplicitAgent to check for
the OpenCode marker (e.g. env.OPENCODE_CLIENT or the correct OpenCode env var)
and return { name: 'opencode' } when present, referencing the
detectExplicitAgent function and KnownAgentName type; alternatively, if you
prefer not to detect OpenCode, remove 'opencode' from the KnownAgentName union
to avoid an unreachable value.
🧹 Nitpick comments (1)
code/core/src/telemetry/detect-agent.ts (1)

80-83: Comment mismatch with actual CI behavior.
The comment says CI is excluded, but the logic (and tests) apply heuristics even in CI. Consider updating the comment to avoid future confusion.

✍️ Suggested comment tweak
-  // 2) Behavioral / fingerprint heuristics (exclude CI to reduce false positives)
+  // 2) Behavioral / fingerprint heuristics (no CI special-casing)

Comment on lines +1 to +63
export type KnownAgentName =
| 'claude-code'
| 'gemini-cli'
| 'cursor'
| 'codex'
| 'opencode'
| 'amp'
| 'unknown';

export type AgentInfo = {
name: KnownAgentName;
};

export type AgentDetection = {
isAgent: boolean;
agent?: AgentInfo;
};

type DetectAgentOptions = {
stdoutIsTTY: boolean;
env: NodeJS.ProcessEnv;
};

function detectExplicitAgent(env: NodeJS.ProcessEnv): AgentInfo | undefined {
// Amp
if (env.AGENT === 'amp') {
return {
name: 'amp',
};
}

// Claude Code
if (env.CLAUDECODE) {
return {
name: 'claude-code',
};
}

// Gemini CLI
if (env.GEMINI_CLI) {
return {
name: 'gemini-cli',
};
}

// OpenAI Codex
if (env.CODEX_SANDBOX) {
return {
name: 'codex',
};
}

// Cursor Agent (proposed / best-effort; Cursor often sets VSCode env vars too)
if (env.CURSOR_AGENT) {
return {
name: 'cursor',
};
}

// Generic "AGENT" marker (unknown implementation)
if (env.AGENT) {
return { name: 'unknown' };
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the detect-agent.ts file to confirm the current state
cat -n code/core/src/telemetry/detect-agent.ts

Repository: storybookjs/storybook

Length of output: 2555


🏁 Script executed:

# Search for any references to 'opencode' in the codebase
rg -i "opencode" --type ts --type tsx --type js --type jsx -B 2 -A 2

Repository: storybookjs/storybook

Length of output: 92


🏁 Script executed:

# Also search for 'OPENCODE' environment variable references
rg "OPENCODE" -B 2 -A 2

Repository: storybookjs/storybook

Length of output: 47


🏁 Script executed:

# Let me search more broadly for 'opencode' with simpler rg command
rg -i "opencode"

Repository: storybookjs/storybook

Length of output: 119


🏁 Script executed:

# Also check git history to see when 'opencode' was added
git log --oneline --all -- code/core/src/telemetry/detect-agent.ts | head -20

Repository: storybookjs/storybook

Length of output: 106


🏁 Script executed:

# Check the actual git diff for that file to understand the context
git log -p --all -- code/core/src/telemetry/detect-agent.ts | head -150

Repository: storybookjs/storybook

Length of output: 47


🏁 Script executed:

# Check the full git history of that commit to understand intent
git show 017acedcc0

Repository: storybookjs/storybook

Length of output: 50382


🏁 Script executed:

# Search for any TODO or FIXME comments near opencode
rg -i "opencode|TODO|FIXME" code/core/src/telemetry/ -B 2 -A 2

Repository: storybookjs/storybook

Length of output: 1327


🌐 Web query:

OpenCode CLI environment variable identification agent

💡 Result:

In OpenCode CLI, the environment variable used to identify the client (agent/client identifier) is:

  • OPENCODE_CLIENT — “Client identifier (defaults to cli)” (set this if you want OpenCode to tag/identify where requests are coming from). [1]

To select which OpenCode “agent” to run, there isn’t an OPENCODE_* env var for that; you choose it via CLI flags:

  • opencode --agent <agent> (TUI) / opencode run --agent <agent> (non-interactive). [1]

Add explicit detection for opencode or remove it from KnownAgentName.

KnownAgentName includes 'opencode' (line 6), but detectExplicitAgent never returns it, so telemetry will never emit that value. Either add detection logic using the appropriate environment variable (OpenCode uses OPENCODE_CLIENT as a client identifier) or remove 'opencode' from the union to avoid a dead value.

🤖 Prompt for AI Agents
In `@code/core/src/telemetry/detect-agent.ts` around lines 1 - 63, The
KnownAgentName union includes 'opencode' but detectExplicitAgent never returns
it; update detectExplicitAgent to check for the OpenCode marker (e.g.
env.OPENCODE_CLIENT or the correct OpenCode env var) and return { name:
'opencode' } when present, referencing the detectExplicitAgent function and
KnownAgentName type; alternatively, if you prefer not to detect OpenCode, remove
'opencode' from the KnownAgentName union to avoid an unreachable value.

@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot bot commented Jan 27, 2026

Package Benchmarks

Commit: 0d8afbe, ran on 28 January 2026 at 11:33:48 UTC

No significant changes detected, all good. 👏

Copy link
Copy Markdown
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

🤖 Fix all issues with AI agents
In `@code/core/src/telemetry/detect-agent.test.ts`:
- Around line 77-79: The test description is misleading: update the test's "it"
description in detect-agent.test.ts to reflect the actual expected return value
of detectAgent (which is AgentInfo | undefined); change the string "returns
isAgent=false when there are no signals" to something like "returns undefined
when there are no signals" so it matches the assertion that detectAgent({
stdoutIsTTY: false, env: {} }) returns undefined and references the detectAgent
function in the test.
🧹 Nitpick comments (1)
code/core/src/telemetry/detect-agent.test.ts (1)

6-58: Good coverage of explicit agent precedence, but consider adding isolated CLAUDECODE test.

The precedence tests thoroughly validate AGENT=amp as highest priority and the fallthrough behavior. However, there's no dedicated test for CLAUDECODE detection in isolation (it's only tested alongside other env vars in lines 20-31).

Consider adding a test for completeness:

🔧 Suggested test case for CLAUDECODE isolation
+  it('detects claude-code via CLAUDECODE', () => {
+    expect(detectAgent({ stdoutIsTTY: true, env: { CLAUDECODE: '1' } })).toEqual({
+      name: 'claude-code',
+    });
+  });
+
   it('detects Gemini CLI via GEMINI_CLI', () => {

Comment on lines +77 to +79
it('returns isAgent=false when there are no signals', () => {
expect(detectAgent({ stdoutIsTTY: false, env: {} })).toEqual(undefined);
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix misleading test description.

The test description says "returns isAgent=false" but the assertion expects undefined. The detectAgent function returns AgentInfo | undefined, not an object with an isAgent field.

📝 Suggested fix
-  it('returns isAgent=false when there are no signals', () => {
+  it('returns undefined when there are no signals', () => {
     expect(detectAgent({ stdoutIsTTY: false, env: {} })).toEqual(undefined);
   });
📝 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
it('returns isAgent=false when there are no signals', () => {
expect(detectAgent({ stdoutIsTTY: false, env: {} })).toEqual(undefined);
});
it('returns undefined when there are no signals', () => {
expect(detectAgent({ stdoutIsTTY: false, env: {} })).toEqual(undefined);
});
🤖 Prompt for AI Agents
In `@code/core/src/telemetry/detect-agent.test.ts` around lines 77 - 79, The test
description is misleading: update the test's "it" description in
detect-agent.test.ts to reflect the actual expected return value of detectAgent
(which is AgentInfo | undefined); change the string "returns isAgent=false when
there are no signals" to something like "returns undefined when there are no
signals" so it matches the assertion that detectAgent({ stdoutIsTTY: false, env:
{} }) returns undefined and references the detectAgent function in the test.

@valentinpalkovic valentinpalkovic added the patch:yes Bugfix & documentation PR that need to be picked to main branch label Jan 28, 2026
@valentinpalkovic valentinpalkovic merged commit 945a876 into next Jan 28, 2026
129 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Core Team Projects Jan 28, 2026
@valentinpalkovic valentinpalkovic deleted the valentin/implement-agent-detection-telemetry branch January 28, 2026 11:39
valentinpalkovic added a commit that referenced this pull request Jan 30, 2026
…etection-telemetry

Telemetry: Add agent detection
(cherry picked from commit 945a876)
@github-actions github-actions bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Jan 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal maintenance User-facing maintenance tasks patch:done Patch/release PRs already cherry-picked to main/release branch patch:yes Bugfix & documentation PR that need to be picked to main branch telemetry

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants