mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
94379db14a
## Summary Adds a public **Vue `CopilotThreadsDrawer`** — a thin wrapper over the shared `<copilotkit-threads-drawer>` Lit element — bringing the Threads-v2 drawer to Vue at parity with the shipped React and Angular verticals. This is the Vue fast-follow tracked in the [CopilotDrawer — Vue wrapper](https://app.notion.com/p/3883aa38185281fc8a2cfb69cd1dd88e) spec. **SDK-only PR** (`packages/vue`). Like the Angular vertical, the example de-fork / demo route is a **separate follow-up** — the Vue examples can't consume the drawer until `@copilotkit/web-components` + a `react-core` release ship *and* the examples support managed Intelligence. Recon during planning corrected the spec's original "cheapest/thinnest wrapper" premise: Vue is thin on element interop (native `isCustomElement` + `v-bind`/`v-on`) but — exactly like Angular — needed an active-thread foundation built. So this ports the full vertical, not just a binding layer. ## What changed (SDK layers) - **`useThreads` augmentation** (`hooks/use-threads.ts`): `enabled` gate, `listError` (genuine list errors, excludes dev/config errors), `isMutating`, `unarchiveThread` / `refetchThreads` / `startNewThread`; plus **`registerThreadStore` core-registry integration** and **`threadEndpoints` list/mutation gating** (React parity). - **Active-thread + drawer-awareness on `CopilotChatConfigurationProvider`**: `setActiveThreadId` / `startNewThread` with the non-explicit-seed override (so thread-switching + "+ New" work under `<CopilotKit>`), and `drawerOpen` / `setDrawerOpen` / `drawerRegistered` / `registerDrawer` with bidirectional mobile (`<768px`) mutual-exclusion. - **Clear-on-fresh in `CopilotChat`**: clears the conversation on a genuine new-thread switch, guarded against initial mount and agent-store swaps. - **Mobile launcher in `CopilotModalHeader`**: renders only when a drawer is registered AND the viewport is mobile. - **The `CopilotThreadsDrawer.vue` wrapper** + barrel export. - **SSR safety:** the wrapper imports the `<copilotkit-threads-drawer>` Lit element **lazily** (`await import(...)` inside `onMounted`, client-only) rather than at module scope. The element evaluates `class … extends HTMLElement` at import time, which crashes Nuxt/Vite SSR (`HTMLElement is not defined`) — a static import would break SSR for **every** `@copilotkit/vue` consumer, not just drawer users. (Found via live Nuxt testing; see Testing.) Load-bearing behaviors carried from the React/Angular rounds: license gate never flashes the locked view (`licensed || pending`, `loading || pending`) and issues no `/threads` fetch while unlicensed; provider-less `localDrawerOpen` fallback; id-keyed per-row slot reconciliation. ## How it was built & reviewed Executed via the `micro-task-execution` three-tier model (curator → decomposition-reviewer → 8 waves, each opus-reviewed) → integration review → **`cr-loop`: 4 seven-agent review rounds + 7 fix batches, converged to zero mandatory findings + a Procedure 3 promotion-audit with zero promotions.** The loop caught and fixed real defects the per-wave reviews missed: a `useThreads` stuck-loading bug on `enabled:false`, a wrong chat-input focus `data-testid` (silent a11y failure), a `CopilotChatToggleButton` fallback regression from the provider change, net-new lint (`no-dupe-keys`, deprecated `:slot`), and — surfaced by the promotion audit as load-bearing on the shipped surfaces — the `registerThreadStore` (inspector visibility) and `threadEndpoints` gating parity gaps. ## Testing **Automated (all green in the worktree):** - `nx run @copilotkit/vue:test` — **99 files / 1061 tests passed**. New coverage: full `useThreads` augmented surface incl. store registration + endpoint gating + mutation guards + `enabled` re-arm; the wrapper's entire 10-event routing table; license pending-vs-resolved gating; delete-active-thread reset; clear-on-fresh (with a mutation-check proving it's non-vacuous); bidirectional mobile mutual-exclusion; `isMobileViewport` guards; the mobile launcher; the `setModalOpen`-undefined contract that `CopilotChatToggleButton` depends on. - `nx run @copilotkit/vue:build` — succeeds (this is the real type gate: `vue-tsc --declaration`); the compiled `dist` exports `CopilotThreadsDrawer`. - `nx run @copilotkit/vue:check-types` — passes. - `pnpm install --frozen-lockfile` — passes (lockfile in sync). - Lint: all new/changed source files are clean. (The package-wide `nx lint` has 173 pre-existing errors, red on `main` and unrelated to this change.) Red-green discipline was applied to every behavioral fix (test written to fail against the bug, then confirmed green after the fix). **Live-verified via a throwaway hacked example** (uncommitted; the examples can't ship managed Intelligence yet, so the committed demo/de-fork is a follow-up): wired the Vue Nuxt demo's runtime to a managed-Intelligence runtime (`CopilotKitIntelligence` + `licenseToken`, creds from a CLI scaffold) and loaded `/threads`. Observed: `/info` reports `mode:"intelligence"`, `licenseStatus:"valid"`, `threadEndpoints:{list,inspect,mutations,realtimeMetadata: true}`; the drawer renders the **real thread list from the platform** (licensed — not the locked or endpoints-unavailable gates), with the Active/All filter, "New thread", per-row Archive/Delete, and the mobile launcher; `CopilotChat` renders beside it; no console errors. This live run is what surfaced the SSR bug above: before the lazy-import fix, `/threads` (and `/`) 500'd with `HTMLElement is not defined`; after it, `/threads` → 200 and the error is gone. (Note: the added node-env regression test `CopilotThreadsDrawer.ssr.test.ts` is a forward-looking smoke guard — current Lit ships a Node-guarded build so vitest-node can't reproduce Nuxt's Vite-SSR resolution; the fix's proof is the live Nuxt run.) ## Release gate Like the React/Angular de-forks, the wrapper depends on `@copilotkit/web-components` being published and a `react-core`/`web-components` release containing the drawer. `packages/vue` publishes alongside. ## Follow-up work (separate PRs, none blocking) Tracked in **ENT-1037** (related to ENT-1035): the cross-framework 767/768 mobile-breakpoint reconciliation, `useThreads.startNewThread` config-error dismissal parity, an identity-guarded `unregisterThreadStore`, and CopilotChat send/connect error-UX parity. The Vue examples are intentionally left as-is (no Vue de-fork). Review feedback (@marthakelly) has been addressed in-branch — see the review reply. 🤖 Generated with [Claude Code](https://claude.com/claude-code)