feat(seer): give the profile embed a real block level - #123901
Open
billyvg wants to merge 7 commits into
Open
Conversation
The `profile` schema already declared `level: ['inline', 'block']`, but both levels rendered the same bare link. The block now previews the profile: a metadata strip (transaction, duration, threads, environment, release, OS, device, received) above a 200px flamechart, from a single fetch of the profile payload. Splits the embed into a directory per the embeds convention, so the flamegraph renderer and speedscope model layer stay out of the bundle until a block actually renders. Two page-level couplings are deliberately avoided: `importProfile` is called directly rather than mounting `ProfileGroupProvider`, which reads `?tid=` off the host URL, and the metadata comes from the payload rather than `useProfileEvents`, which reads host page filters that have nothing to do with a specific profile. The left-heavy/time-ordered toggle keeps its state local, with a test asserting it never touches the router. Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
Moved to components/profile/profileLink.tsx. Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
Moved to components/profile/profile.spec.tsx. Claude-Session: https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
This was referenced Sep 9, 2026
The profile embed's story rendered the schema's static example, whose profile id is made up — so the new block level always 404'd there and fell back to the bare link. Swap it for a `ProfileEmbedStory` that pulls the org's most recent transaction-based profile, matching what the other block-level embeds (release, replay, savedQuery) already do. `has:profile.id` keeps the search off continuous profiles, which are addressed by profiler id plus a time range and so cannot be expressed in this embed's schema. Claude-Session: https://claude.ai/code/session_01PHE7yFBmGH1Rv1nmzGqwys
Contributor
Story previewsPreview the stories changed in this PR on the Vercel deployment: Preview deployment: https://sentry-llrbppijx.sentry.dev |
The profile schema was written when both levels rendered the same link, so its description says nothing about the levels and its single example is implicitly inline. Level is decided by placement -- a tag alone in a paragraph is block, a tag inside a sentence is inline -- so the description and the per-level examples are the only things that teach the agent to put a profile on its own line. Without them the new block preview would rarely be what renders. Follows how `issue` and `replay` document their levels, including the "do NOT duplicate any of that data as text" instruction that keeps the agent from restating the metadata strip in prose. Claude-Session: https://claude.ai/code/session_01PHE7yFBmGH1Rv1nmzGqwys
Member
Author
|
bugbot review |
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8009a56. Configure here.
"Open in Profiling" encoded the previewed viewport as `fov` alongside `type: 'flamechart'`, but the flamegraph page's query decoder has no `type` key -- it picks call-order vs left-heavy from `sorting`, which defaults to call order. The preview defaults to left-heavy, so the rect was replayed against a differently sorted tree and pointed at unrelated frames. Send `sorting` instead, from a single `VIEW_MODE_SORT` map that also feeds the preview's own FlamegraphModel, so the two cannot drift apart again. The spec only asserted the button existed, which is how this got through; it now asserts the href carries the sort, in both toggle positions. Claude-Session: https://claude.ai/code/session_01PHE7yFBmGH1Rv1nmzGqwys
billyvg
marked this pull request as ready for review
September 9, 2026 16:51
billyvg
added a commit
that referenced
this pull request
Sep 9, 2026
Adds an `event` Seer markdown embed for a single error event inside an issue. Inline renders a compact link; block renders the event's title, message, culprit and context. One of four independent branches adding single-resource Seer embeds — see also #123901 (profile). They all touch `schemas.ts`, `index.ts`, the stories page and the generated widget JSON, so whichever merges first leaves the rest needing a rebase plus a `pnpm gen:embed-widgets` re-run. ### The `view` field A single event holds exactly one value per tag, so showing "just that tag" on its own would say nothing. `view` therefore controls what the block adds *beneath* the summary: | `view` | Renders | | --- | --- | | `summary` (default) | the event on its own | | `tags` | the event's full tag list | | `tag` + `tagKey` | how that tag is distributed across the whole issue | `tag` without a `tagKey` falls back to `summary` and issues no request — there's a test for that. ### Notes for review - Tag links point at `distributions/`, not the legacy `tags/` paths, which only redirect there. - The block fetches via `groupEventApiOptions` with an explicitly empty `environments`, rather than the `useGroupEvent` hook, which reads `useLocation()` — an embed must not inherit the host page's filters. Same reasoning as the README rule about not touching host page state. - `EventTagsView` falls back to a plain key/value list when the events API omits `projectSlug`, since `EventTagsTree` needs one to load the project it renders rows against. - `TagDistribution` is pure, so the `tag` view cannot reach the host page's URL. ### Testing 8 tests covering both inline title forms, the block summary, both tag views, the no-`tagKey` fallback, the missing-`projectSlug` fallback, and the error state. The whole `seer/markdown` suite passes (24 suites / 113 tests); oxlint and oxfmt are clean, and `pnpm gen:embed-widgets` produces no diff. Closes https://linear.app/getsentry/issue/CW-1958/add-error-instance-embed 🤖 Generated with [Claude Code](https://claude.ai/code) https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
billyvg
added a commit
that referenced
this pull request
Sep 9, 2026
Adds two Seer markdown embeds for Explore > Agents: - **`conversation`** — one AI agent conversation. Inline renders a link; block renders the transcript with its LLM call, token, cost and tool totals. - **`conversationsQuery`** — the conversations list filtered by a search. Inline renders a link; block previews the first five matching rows with duration, message count, errors and cost. Both are gated on `organizations:gen-ai-conversations`, which already exists in `temporary.py`, so neither reaches the agent until an org has it. The last of four independent branches adding single-resource Seer embeds — see also #123901 (profile), #123905 (event) and #123906 (log). They all touch `schemas.ts`, `index.ts`, the stories page and the generated widget JSON, so whichever merges first leaves the rest needing a rebase plus a `pnpm gen:embed-widgets` re-run. ### Notes for review Both blocks avoid the route-level machinery, because it is URL-coupled and an embed must not touch the host page's history (`embeds/README.md`): - The list block builds its own query rather than using `useConversations`, which takes no arguments and reads cursor/filters through nuqs. - The transcript composes `MessagesPanel` + `ConversationAggregatesBar` directly rather than `ConversationViewContent`, which writes its tab and detail-tab state back to the URL. Message selection is local `useState`, with a test asserting the router never changes. Two shape details worth a look: - **Content flattening.** `useConversations` normalizes `firstInput`/`lastOutput` before handing rows out, but the raw endpoint returns `string | {type, text}[] | null`. Since the block calls the endpoint directly, it flattens them itself, then strips markdown to a single line for the cell. - **The agent filter lives in two places.** The list view keeps it in its own `agent` URL param and folds it into the span query only when calling the API. The link mirrors the former, the block the latter, so both are filtered identically. Ordering also differs: the endpoint returns by relevance, and the list view sorts newest-first before rendering, so the preview re-sorts to match. ### Testing 10 tests across both embeds — inline hrefs and their padded time windows, the transcript, aggregates, API-title-wins-over-tag-title, selection staying local, the error state, the row preview with ordering and formatting, content-part flattening, and the empty state. The whole `seer/markdown` suite passes; oxlint and oxfmt are clean, and `pnpm gen:embed-widgets` produces no diff. Closes https://linear.app/getsentry/issue/CW-2003/add-ai-conversations 🤖 Generated with [Claude Code](https://claude.ai/code) https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ
ryan953
reviewed
Sep 9, 2026
Comment on lines
+297
to
+301
| <Container | ||
| data-test-id="seer-profile-flamechart" | ||
| height={PREVIEW_HEIGHT} | ||
| position="relative" | ||
| > |
Member
Member
Author
There was a problem hiding this comment.
fwiw the full page is also scrolled to the bottom, but it has a minimap view to see where you are. I'll play around and see what I can do
ryan953
approved these changes
Sep 9, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.


The
profileschema already declaredlevel: ['inline', 'block'], but both levels rendered the same bare link. This gives the block level a real preview: a metadata strip above a 200px flamechart, from a single fetch of the profile payload.One of four independent branches adding single-resource Seer embeds. The others (
event,log,conversation) touch the same shared files —schemas.ts,index.ts, the stories page, and the generated widget JSON — so whichever merges first will make the rest need a trivial rebase.What the block renders
ProfileLink, a local Left-heavy / Time-ordered toggle, and an "Open in Profiling" button that deep-links the previewed viewport.FlamegraphPreviewin a fixed-height container.Notes for review
Two page-level couplings are deliberately avoided, per the rule in
embeds/README.mdthat an embed must not touch the host page's URL or history:importProfileis called directly instead of mountingProfileGroupProvider, which reads?tid=off the host URL — in a Seer conversation that would silently pick the thread from an unrelated query param.useProfileEvents, which resolves its scope from host page filters that have nothing to do with a specific profile. There is no metadata-only endpoint, so the full payload is fetched either way and the flamechart is close to free once it is.The view toggle is local
useState, with a test asserting it never writes to the router.Splitting the embed into a directory follows the convention in
.claude/skills/seer-embed, and keeps the flamegraph renderer and speedscope model layer out of the bundle until a block actually renders.Testing
profile.spec.tsxcovers the inline href, the block metadata strip and flamechart, the toggle staying local, and degrading to the link on a 404 and on a continuous-chunk payload. The whole embed suite passes (19 suites / 101 tests); oxlint, oxfmt and typecheck are clean.The flamechart renders unmocked under jsdom —
jest-canvas-mockis already insetupFiles.Closes https://linear.app/getsentry/issue/CW-1945/add-profile-embed
🤖 Generated with Claude Code
https://claude.ai/code/session_016YUmhMZLo8geXJa93daPEQ