-
-
Notifications
You must be signed in to change notification settings - Fork 10.1k
Agentic Setup: Add observability #34510
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Sidnioulz
merged 35 commits into
project/sb-agentic-setup
from
sidnioulz/agentic-telemetry-ws1
Apr 14, 2026
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
12e09ed
wip(telemetry): design doc + feature extraction spike
Sidnioulz 3155701
feat(telemetry): add ai-setup-evidence event type
Sidnioulz 2f2e6a9
feat(telemetry): preserve userSince for agents in CI
Sidnioulz 559a09a
feat: add mock telemetry receiver for local debugging
Sidnioulz 1fea584
refactor(ghost-stories): move trigger from modal to 10min delay, simp…
Sidnioulz 1cb3610
feat(ai): thread traits accumulator through prompt generation
Sidnioulz 5f11032
feat(ai): add telemetry, baseline snapshot, and frontmatter to sb ai …
Sidnioulz 241710a
feat(telemetry): add evidence-based ai-setup completion tracking at C…
Sidnioulz cc92a8c
fix: update tests for ghost-stories, withTelemetry, and detect-agent …
Sidnioulz ec41d25
Apply suggestion from @Sidnioulz
Sidnioulz a6f4f1f
Apply suggestion from @Sidnioulz
Sidnioulz 0155a76
Apply suggestion from @Sidnioulz
Sidnioulz eec68c2
Apply suggestion from @Sidnioulz
Sidnioulz b571cf5
Apply suggestion from @Sidnioulz
Sidnioulz 090c511
refactor: rename ai-setup-evidence to ai-prepare-evidence, add ai-pre…
Sidnioulz fec53a5
feat: create ai-prepare-evidence module with evidence collection, sto…
Sidnioulz 8606a4a
refactor: replace inline AiSetupPendingRecord with type import from a…
Sidnioulz a529bcb
refactor: move AiSetupPendingRecord and isStoryCreatedByAISetup to te…
Sidnioulz d22240d
refactor: remove evidence collection from withTelemetry, import from …
Sidnioulz f60ecfe
feat: fire ai-prepare evidence from doTelemetry with story index for …
Sidnioulz 1826b68
test: add unit tests for ai-prepare-evidence module
Sidnioulz a6a2532
chore: clean up dead detect-agent mock, fix test name for agent detec…
Sidnioulz 82f7bcd
feat: add AI story scoring to ghost stories channel with CPU capacity…
Sidnioulz 8c9eaa0
Fix linting
Sidnioulz c891c83
Update implementation
Sidnioulz b9bb015
Update test mocks and fixtures
Sidnioulz 50ddc1f
Remove spike script for feature adoption data flow
Sidnioulz f802462
Align type imports between two files
Sidnioulz f351600
Flush event cache when ai prepare event is expired
Sidnioulz 9e795d3
Apply suggestion from @Sidnioulz
Sidnioulz f00c02f
Apply suggestion from @Sidnioulz
Sidnioulz 1687113
Merge branch 'project/sb-agentic-setup' into sidnioulz/agentic-teleme…
Sidnioulz 956d2fe
Merge telemetry loggers
Sidnioulz 8119825
Switch delayed analytics to a 4m timeout
Sidnioulz f51a483
Fix timings in tests
Sidnioulz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
code/core/src/core-server/server-channel/ai-prepare-channel.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| import type { Channel } from 'storybook/internal/channels'; | ||
| import { | ||
| AI_PREPARE_ANALYTICS_REQUEST, | ||
| AI_PREPARE_ANALYTICS_RESPONSE, | ||
| } from 'storybook/internal/core-events'; | ||
| import { | ||
| getLastEvents, | ||
| getStorybookMetadata, | ||
| isStoryCreatedByAIPrepare, | ||
| telemetry, | ||
| } from 'storybook/internal/telemetry'; | ||
| import type { CoreConfig, Options } from 'storybook/internal/types'; | ||
| import { logger } from 'storybook/internal/node-logger'; | ||
|
|
||
| import { runGhostStories } from '../utils/ghost-stories/run-story-tests.ts'; | ||
| import type { StoryIndexGenerator } from 'storybook/internal/core-server'; | ||
| import { waitForIdleVitest } from '../utils/wait-for-idle-vitest.ts'; | ||
|
|
||
| export function initAIAnalyticsChannel( | ||
| channel: Channel, | ||
| options: Options, | ||
| coreOptions: CoreConfig, | ||
| getStoryIndexGeneratorPromise?: () => Promise<StoryIndexGenerator> | undefined | ||
| ) { | ||
| if (coreOptions.disableTelemetry) { | ||
| return channel; | ||
| } | ||
|
|
||
| /** Send analytics about the ai prepare workflow when requested*/ | ||
| channel.on(AI_PREPARE_ANALYTICS_REQUEST, async () => { | ||
| const stats: { | ||
| fileCount?: number; | ||
| storyCount?: number; | ||
| testRunDuration?: number; | ||
| } = {}; | ||
|
|
||
| try { | ||
| const lastEvents = await getLastEvents(); | ||
| const lastAIPrepare = lastEvents?.['ai-prepare']; | ||
| const lastPrepareStoryScoringRun = lastEvents?.['ai-prepare-story-scoring']; | ||
|
|
||
| // Only run if sb ai prepare has been called | ||
| if (!lastAIPrepare) { | ||
| return; | ||
| } | ||
|
|
||
| // Already ran once for this project — never run again | ||
| if (lastPrepareStoryScoringRun) { | ||
| return; | ||
| } | ||
|
|
||
| const metadata = await getStorybookMetadata(options.configDir); | ||
| const isReactStorybook = metadata?.renderer?.includes('@storybook/react'); | ||
| const hasVitestAddon = | ||
| !!metadata?.addons && | ||
| Object.keys(metadata.addons).some((addonKey) => | ||
| addonKey.includes('@storybook/addon-vitest') | ||
| ); | ||
|
|
||
| // For now this is gated by React + Vitest | ||
| if (!isReactStorybook || !hasVitestAddon) { | ||
| return; | ||
| } | ||
|
|
||
| // Wait for any running tests to finish before launching scoring, so we don't | ||
| // disturb end user activities. | ||
| const isIdle = await waitForIdleVitest(); | ||
| if (!isIdle) { | ||
| logger.debug('AI_PREPARE_ANALYTICS_REQUEST timed out waiting for vitest to be available.'); | ||
| return; | ||
| } | ||
|
|
||
| // Fetch AI-generated stories and score them with the ghost stories metrics, if any are found. | ||
| const generatorPromise = getStoryIndexGeneratorPromise?.(); | ||
| if (!generatorPromise) { | ||
| logger.debug( | ||
| 'AI_PREPARE_ANALYTICS_REQUEST could not proceed as the index generator is not ready.' | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| const generator = await generatorPromise; | ||
| const indexAndStats = await generator.getIndexAndStats(); | ||
| if (!indexAndStats) { | ||
| logger.debug('AI_PREPARE_ANALYTICS_REQUEST could not proceed as the index is not ready.'); | ||
| return; | ||
| } | ||
|
|
||
| const aiStoryFiles = new Set<string>(); | ||
| let aiStoryCount = 0; | ||
| for (const entry of Object.values(indexAndStats.storyIndex.entries)) { | ||
| if (isStoryCreatedByAIPrepare(entry)) { | ||
| aiStoryFiles.add(entry.importPath); | ||
| aiStoryCount++; | ||
| } | ||
| } | ||
|
|
||
| if (aiStoryFiles.size > 0) { | ||
| const aiTestRunResult = await runGhostStories([...aiStoryFiles]); | ||
| telemetry('ai-prepare-story-scoring', { | ||
| stats: { | ||
| fileCount: aiStoryFiles.size, | ||
| storyCount: aiStoryCount, | ||
| testRunDuration: aiTestRunResult.duration, | ||
| }, | ||
| results: aiTestRunResult.summary, | ||
| ...(aiTestRunResult.runError ? { runError: aiTestRunResult.runError } : {}), | ||
| }); | ||
| } else { | ||
| telemetry('ai-prepare-story-scoring', { | ||
| stats: { | ||
| fileCount: 0, | ||
| storyCount: 0, | ||
| testRunDuration: 0, | ||
| }, | ||
| runError: 'No stories found that were generated by ai setup', | ||
| }); | ||
| } | ||
| } catch { | ||
| telemetry('ai-prepare-story-scoring', { | ||
| stats, | ||
| runError: 'Unknown error during AI story scoring', | ||
| }); | ||
| } finally { | ||
| // we don't currently do anything with this, but will be useful in the future | ||
| channel.emit(AI_PREPARE_ANALYTICS_RESPONSE); | ||
| } | ||
| }); | ||
|
|
||
| return channel; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was caught up during my review of the existing telemetry, we're not putting this addon in our own satellites bucket.