-
Notifications
You must be signed in to change notification settings - Fork 49
feat(thread): new ChatX conversation thread (behind useNewChatThread flag) #3022
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
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
dcb5f20
new markdown, new UI based on quill (publish it first)
adamleithp e4e91a3
wip
adamleithp 14be108
session view stuff
adamleithp 1fa8296
feat(thread): restore user-message chrome, gate shared changes, fix a…
adamleithp ab9a444
feat(thread): footer + status markers in new thread, fix stuck compac…
adamleithp 8c2ecf9
fix(thread): address review — stale tool-group label, PascalCase name…
adamleithp 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # ChatX Thread Rebuild — Build Spec | ||
|
|
||
| Status: in progress. Source of decisions: grilling session 2026-06-27. | ||
|
|
||
| ## Thesis | ||
|
|
||
| Replace the virtualized thread (`ConversationView` + `VirtualizedList`) with shadcn | ||
| **Base-UI** chat primitives, renamed `ChatX`. Non-virtualized, `content-visibility: auto`, | ||
| minimal DOM, close to the shadcn examples. Primitives are built in **quill**; the app-side | ||
| thread is rebuilt in the **code** repo. | ||
|
|
||
| ## Provenance | ||
|
|
||
| The primitives are vendored from the shadcn `base-mira` registry: | ||
|
|
||
| - `https://ui.shadcn.com/r/styles/base-mira/{message-scroller,message,bubble,marker,attachment}.json` | ||
| - The scroll **engine** is the published headless package `@shadcn/react` (MIT, exports | ||
| `./message-scroller`). The styled file is a thin wrapper — same shape as quill's | ||
| `Badge` wrapping `@base-ui/react`. We take `@shadcn/react` as a runtime dep of the | ||
| quill primitives package and wrap it in quill conventions. | ||
|
|
||
| ## Where | ||
|
|
||
| - **Primitives**: `posthog/packages/quill/packages/primitives/src/chat-*.tsx` | ||
| (+ colocated `chat-*.css`, `chat-*.stories.tsx`), exported from `index.ts`. | ||
| Conventions: `useRender` / `mergeProps` / `cva` / `data-quill` / `cn` from `./lib/utils`, | ||
| 4-space indent, single quotes. | ||
| - **App thread**: code repo `packages/ui` — new `<ChatThread>` replacing `ConversationView`. | ||
| - Flow: build in quill → local-link → integrate → publish beta → bump catalog. | ||
|
|
||
| ## Primitives (v1 = four) | ||
|
|
||
| 1. **ChatMessageScroller** (Provider / Root / Viewport / Content / Item / Button + 3 hooks). | ||
| Thin wrap of `@shadcn/react/message-scroller`. Non-virtualized. `autoScroll`, | ||
| `defaultScrollPosition="end"`, `scrollPreviousItemPeek≈64`, `scrollAnchor` on | ||
| turn-start items. Imperative scroll state via data-attrs; no React state on scroll. | ||
| 2. **ChatMessage** (Group / Avatar / Content / Header / Footer). `align="start|end"`. | ||
| Avatar first-class, omitted in our render. | ||
| 3. **ChatBubble** (Content / Reactions / Group). Assistant = `ghost` (no bg, full-width); | ||
| user = filled. | ||
| 4. **ChatMarker** (Icon / Content) — the recursive one. **Diverges from stock shadcn | ||
| Marker**: when given a `body`, renders as a Base-UI Collapsible — hover shows a chevron | ||
| + `bg-fill-hover`, click toggles, expanded renders the body. No body → flat status line | ||
| (stock shadcn). Uncontrolled `defaultOpen` + optional `open` / `onOpenChange`. | ||
| Pairs with `Spinner` + shimmer for live state. | ||
|
|
||
| Deferred: `ChatAttachment` (except trivial mention chips), `BubbleReactions`. | ||
|
|
||
| ## Mapping (app layer) | ||
|
|
||
| - **User turn** → `ChatMessage align="end"` → filled `ChatBubble` → text (+ mention chips). | ||
| - **Assistant turn** → `ChatMessage align="start"` → `ghost ChatBubble` → bare markdown. | ||
| - **Single tool** → `ChatMarker` with `body` = injected detail (`<ReadContent/>`, | ||
| `<EditDiff/>` — reused existing renderers; primitive is chrome-only). | ||
| - **Tool group (completed turn)** → summary `ChatMarker` ("Read 3 files · Edited 1") whose | ||
| `body` = the per-tool child `ChatMarker`s. | ||
| - **Status / thought / error / compact / cancelled** → `ChatMarker` | ||
| (`default` / `border` / `separator`). | ||
| - **MCP app iframes** → top-level rows, outside grouping, IntersectionObserver | ||
| mount/unmount (no state preservation — acceptable). | ||
|
|
||
| ## Grouping / collapse | ||
|
|
||
| - `mode={all|partial|none}` on **`<ChatThread>`** (app), not the primitive. App maps | ||
| mode → per-marker `defaultOpen`: `none`→true, `all`→false, `partial`→`isActiveTurn`. | ||
| - **Live→complete**: live turn renders expanded markers (Spinner/shimmer); on completion | ||
| the grouper **swaps row identity** → one collapsed summary marker mounts fresh. Keep | ||
| `createIncrementalThreadGrouper`. No controlled-state flipping. | ||
|
|
||
| ## Escape hatch (heavy rows) | ||
|
|
||
| Heavy rows opt into IntersectionObserver mount/unmount + placeholder. Off-screen MCP apps | ||
| unmount. `content-visibility: auto` saves paint, not React mount cost — this caps live | ||
| iframe processes. | ||
|
|
||
| ## Anchoring / streaming | ||
|
|
||
| - Anchor = user message when present, else turn's first assistant row; `scrollAnchor` on | ||
| those items only. | ||
| - `content-visibility: auto` + tuned `contain-intrinsic-size` per row type. Accept-and-tune | ||
| for v1; leave a seam for a measured-size cache if the 1000-turn stress shows drift. | ||
|
|
||
| ## Build order | ||
|
|
||
| 1. Scroller + dummy rows + 1000-turn stress story (prove thesis). | ||
| 2. `ChatMarker` (all variants / fill levels). | ||
| 3. `ChatMessage` + `ChatBubble`. | ||
| 4. Link → `<ChatThread>` (parse→group→primitives, `mode`, MCP mounting) behind existing composer. | ||
| 5. Stress real thread, tune sizes. | ||
|
|
||
| Each primitive ships `*.stories.tsx` with shadcn-shaped fixtures. | ||
|
|
||
| ## Kept untouched | ||
|
|
||
| Existing composer; event→item parse; optimistic merge; incremental grouper; tool detail renderers. |
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
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
21 changes: 21 additions & 0 deletions
21
packages/ui/src/features/sessions/components/ThreadView.tsx
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,21 @@ | ||
| import { | ||
| ConversationView, | ||
| type ConversationViewProps, | ||
| } from "@posthog/ui/features/sessions/components/ConversationView"; | ||
| import { ChatThread } from "@posthog/ui/features/sessions/components/chat-thread/ChatThread"; | ||
| import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore"; | ||
|
|
||
| /** | ||
| * Picks the conversation renderer at the mount boundary: the experimental ChatX thread when | ||
| * `useNewChatThread` is on, otherwise the production `ConversationView`. Switching at the parent | ||
| * (rather than early-returning inside `ConversationView`) keeps both components' hook order stable | ||
| * across toggles. Flip it in Settings → Experimental. | ||
| */ | ||
| export function ThreadView(props: ConversationViewProps) { | ||
| const useNewChatThread = useSettingsStore((s) => s.useNewChatThread); | ||
| return useNewChatThread ? ( | ||
| <ChatThread {...props} /> | ||
| ) : ( | ||
| <ConversationView {...props} /> | ||
| ); | ||
| } |
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.
Uh oh!
There was an error while loading. Please reload this page.