mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
b24c3e4135
Redesigns the shared `<copilotkit-threads-drawer>` element (`@copilotkit/web-components`) to the new Figma UX, keeping the React, Vue, and Angular wrappers in lockstep. Pure-VIEW change — no `@copilotkit/core`, runtime, or `useThreads` changes. **Ticket:** [ENT-1051](https://linear.app/copilotkit/issue/ENT-1051) · **Figma:** [Thread Drawer](https://www.figma.com/design/feSsBJw1qCfLp0JNnOurrJ/CopilotKit-Intelligence?node-id=723-78) · **Spec:** [Notion](https://app.notion.com/p/3953aa381852819ab464dae3894e7f18) ## What changed - **Header** → right-aligned icon row. On desktop it holds the **collapse** toggle (sidebar glyph); on mobile the **close** toggle. No title text, no "+ New" pill. Optional `slot="header"` preserved (empty by default; the toggle right-aligns after it). - **New Conversation** row (plus-square + label) below the header — keeps `part="new-thread-button"` + the `new-thread` event. - **Recent Conversations** heading + **funnel** filter icon → Active/All popover. Preserves `_filter` + `filter-change` and `part="filter-active"`/`filter-all"`. - **Per-row kebab menu** (⋮) holding Archive/Unarchive + Delete — preserves those events + parts. An open kebab now shields the rest of the list from hover so it reads as a single surface (see Review fixes). - **Delete confirm** is a native `<dialog>` opened with `showModal()` (browser top layer), centered over the drawer's visible box — it can't paint under other UI or drop below the fold. jsdom falls back to the `open` attribute. - **Archived rows** render italic/muted inline in the "All" view. - **Desktop collapse** → `collapsed` / `collapsible` props (default **expanded**) + a `collapse-change` event / `CollapseChangeDetail`. Collapsing sets `--cpk-drawer-reserved-width: 0` on the document root so the host grid reclaims the column with no hydration flicker. - **Unified floating cluster** (Figma "closed" mockup) = `[sidebar-toggle] [+ New Conversation]`, shown in both the mobile-closed and desktop-collapsed states. Mobile stays an off-canvas modal (backdrop / Escape / focus-trap). ## Compatibility - All existing `::part()` names and events are preserved; only **additive** parts are introduced: `collapse-toggle`, `close-toggle`, `section-heading`, `filter-toggle`, `row-menu`, `row-menu-popover`, `launcher-cluster`, `launcher`, `launcher-new-thread`, plus `confirm-dialog`/`confirm-cancel`/`confirm-delete`/`backdrop`. One additive event: `collapse-change`. - Additive wrapper props: `recentLabel` (all frameworks); `collapsible`/`collapsed` + `onCollapseChange` (React) / equivalents in Vue & Angular. - **Usage note (now in the docs):** the drawer and `<CopilotChat>` must share a chat-configuration provider so the drawer drives the chat — `CopilotChatConfigurationProvider` (React/Vue) / `provideCopilotChatConfiguration()` (Angular). The v2 `CopilotKitProvider` does not provide that context on its own. - Verified: **no example `::part()` theme changes required** — every example themes the drawer via inherited `--cpk-drawer-*` custom properties. ## Descoped / changed during development (re: earlier review) - **Client-side search was removed at the designer's request.** There is **no** search UI, `search` event, `search-toggle`/`search-input` part, or `onSearch` wrapper prop in the shipped element. Any remaining "search" mention in older comments is stale. - **Desktop collapse was briefly backed out, then re-restored** per the designer (commit `8bfd245305`). The shipped element **has** collapse (`collapsed` is a live public property — it was not removed). ## Review fixes (commit `0b4f6ca392`) Addressing @MikeRyanDev and @marthakelly: - **`core/threads.ts`** — a full-list refetch (filter-change / retry) now clears `fetchMoreError` on both `listRequested` and `listSucceeded`, so the inline "couldn't load more — retry" banner no longer survives onto a fresh list. - **Escape while confirming delete** — the host keydown handler now consumes Escape while a confirmation is open; previously the bubbled keydown fell through and closed the whole mobile drawer along with the confirmation. - **Open kebab menu shields the list** — `.list.menu-open .row:not(.menu-open)` gets `pointer-events: none`, so other rows no longer reveal their kebab / paint a host `::part(row):hover` background around or behind the open popover. Click-away dismissal is preserved via the existing document pointerdown handler. (Verified live in the langgraph-js example.) - **Docs token** — dropped the removed `--cpk-drawer-rail-width` from the web-components README. ## Testing All suites run via `nx`, green through each package's lefthook pre-commit gate: - `@copilotkit/web-components` — **92** drawer element tests + `:build` green. Covers header collapse/close toggles, New Conversation, funnel filter switch, `recentLabel`, kebab open + archive/delete routing, confirm-dialog gating + native cancel + **backdrop-click dismiss**, **Escape-while-confirming (no drawer close)**, **open-menu row shield**, collapse/cluster/column-reclaim, archived-italic, preserved parts/events, `header` slot + `label` aria-labels. - `@copilotkit/core` — **553** tests incl. the new `clears a lingering fetchMoreError when a full list refetch succeeds`. - `@copilotkit/react-core` — CopilotThreadsDrawer suite + full package **1419** green. - `@copilotkit/vue` — **32** incl. SSR + the `collapsible` boolean-prop-default regression test. - `@copilotkit/angular` — CopilotThreadsDrawer spec **35** (incl. **scoped-chat-input focus**: prefers the ancestor `copilot-chat-view` over the document-global fallback); full package **178**. ## Follow-on - Docs (screenshot + reference/guide) on the release-gated docs PR **#5780**. - Release (`web-components` + `react-core` + `vue` + `angular`, lockstep) + CLI scaffolding bump. - Example grid/theme updates ride the release in **#5828**. - **[ENT-1080](https://linear.app/copilotkit/issue/ENT-1080)** — dedup the per-wrapper `findChatInput` / open-state fallback (marthakelly #6, deliberately deferred as a cross-package refactor). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
CopilotKit - React Core
✨ Why CopilotKit?
- Minutes to integrate - Get started quickly with our CLI
- Framework agnostic - Works with React, Next.js, AGUI and more
- Production-ready UI - Use customizable components or build with headless UI
- Built-in security - Prompt injection protection
- Open source - Full transparency and community-driven
🧑💻 Real life use cases
Deploy deeply-integrated AI assistants & agents that work alongside your users inside your applications.
🖥️ Code Samples
Drop in these building blocks and tailor them to your needs.
Build with Headless APIs and Pre-Built Components
// Headless UI with full control
const { visibleMessages, appendMessage, setMessages, ... } = useCopilotChat();
// Pre-built components with deep customization options (CSS + pass custom sub-components)
<CopilotPopup
instructions={"You are assisting the user as best as you can. Answer in the best way possible given the data you have."}
labels={{ title: "Popup Assistant", initial: "Need any help?" }}
/>
// Frontend actions + generative UI, with full streaming support
useCopilotAction({
name: "appendToSpreadsheet",
description: "Append rows to the current spreadsheet",
parameters: [
{ name: "rows", type: "object[]", attributes: [{ name: "cells", type: "object[]", attributes: [{ name: "value", type: "string" }] }] }
],
render: ({ status, args }) => <Spreadsheet data={canonicalSpreadsheetData(args.rows)} />,
handler: ({ rows }) => setSpreadsheet({ ...spreadsheet, rows: [...spreadsheet.rows, ...canonicalSpreadsheetData(rows)] }),
});
Integrate In-App CoAgents with LangGraph
// Share state between app and agent
const { agentState } = useCoAgent({
name: "basic_agent",
initialState: { input: "NYC" }
});
// agentic generative UI
useCoAgentStateRender({
name: "basic_agent",
render: ({ state }) => <WeatherDisplay {...state.final_response} />,
});
// Human in the Loop (Approval)
useCopilotAction({
name: "email_tool",
parameters: [
{
name: "email_draft",
type: "string",
description: "The email content",
required: true,
},
],
renderAndWaitForResponse: ({ args, status, respond }) => {
return (
<EmailConfirmation
emailContent={args.email_draft || ""}
isExecuting={status === "executing"}
onCancel={() => respond?.({ approved: false })}
onSend={() =>
respond?.({
approved: true,
metadata: { sentAt: new Date().toISOString() },
})
}
/>
);
},
});
// intermediate agent state streaming (supports both LangGraph.js + LangGraph python)
const modifiedConfig = copilotKitCustomizeConfig(config, {
emitIntermediateState: [
{
stateKey: "outline",
tool: "set_outline",
toolArgument: "outline",
},
],
});
const response = await ChatOpenAI({ model: "gpt-4o" }).invoke(
messages,
modifiedConfig,
);
🏆 Featured Examples
Documentation
To get started with CopilotKit, please check out the documentation.