mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
8c629c147b
## What Issue #3388 asked for a way to put a card into the chat transcript from frontend code, without a tool call and without adding to the conversation the model reads. **That already ships.** A message with `role: "activity"` renders standalone in the transcript, and `AbstractAgent.prepareRunAgentInput` strips every activity message from the run payload: ```js prepareRunAgentInput(e) { let t = structuredClone_(this.messages).filter(e => e.role !== `activity`); ... } ``` The gap was documentation. `renderActivityMessages` is only documented for **backend-emitted** activities (mastra background-tasks, a2a, mcp-apps), so the frontend-driven path was undiscoverable. This PR adds the missing guide page and a test that pins the behavior. ## Changes | File | Why | | --- | --- | | `showcase/shell-docs/.../generative-ui/frontend-cards.mdx` | New "Frontend-Driven Cards" guide | | `showcase/shell-docs/.../generative-ui/meta.json` | Sidebar entry (6-line insertion) | | `packages/react-core/.../CopilotChatFrontendActivityCard.e2e.test.tsx` | Pins both halves of the contract | No source changes. Behavior is unchanged; this documents and locks what already works. ## The non-obvious part The card must be added via the agent returned by `useAgent()`. An agent instance constructed and held outside React is **not** the instance the chat renders, so messages added to it silently never appear. This cost me a debugging round while verifying, and it is called out as a warning callout in the docs. ## Testing **1. New test passes against clean `origin/main`** (run in a worktree at `96cf7aa55f`, with `@copilotkit/shared` and `@copilotkit/core` rebuilt from the worktree so the test is not reading a stale dist): ``` ✓ src/v2/components/chat/__tests__/CopilotChatFrontendActivityCard.e2e.test.tsx (2 tests) 72ms Test Files 1 passed (1) Tests 2 passed (2) ``` **2. Mutation-checked, so neither assertion is self-fulfilling.** Drop the renderer registration → the render test fails: ``` × renders a card added from frontend code, with no tool call 1068ms Tests 1 failed | 1 passed (2) ``` Swap the card from `role: "activity"` to `role: "assistant"` → it reappears in the payload, so the exclusion is real and specific to `activity`: ``` AssertionError: expected [ 'user', 'assistant' ] to deeply equal [ 'user' ] ``` **3. Neighboring test unaffected on the same base:** ``` ✓ src/v2/components/chat/__tests__/CopilotChatMessageView.test.tsx (16 tests) 53ms Tests 16 passed (16) ``` **4. Independent probe of the filter** against the pinned `@ag-ui/client` 0.0.57: ``` agent.messages roles: [ 'user', 'activity' ] run input roles : [ 'user' ] ``` **5. `tsc --noEmit`** — zero errors in the new file. Remaining errors in this workspace are in files this PR does not touch (`MCPAppsActivityRenderer.tsx`, `CopilotKitInspector.tsx`) and are artifacts of a hand-assembled local `node_modules`; CI has the real install. **6. `oxfmt --check`** — clean. **7. Docs checks** — `meta.json` validated as JSON; internal link uses the house `/generative-ui/...` form (no `/docs` prefix); `Callout type="warn"` matches the dominant existing usage; import paths verified against the real `@copilotkit/react-core/v2` barrel exports. ## Follow-up Leaving #3388 open until this lands, then closing it with a pointer to the new page. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for frontend-driven activity cards that render in chat transcripts without being sent to the agent or language model. - Added documentation covering activity card renderers, schemas, registration, payload filtering, snapshots, and limitations. - Added a new “Frontend-Driven” section to the Generative UI documentation navigation. - **Tests** - Added end-to-end coverage for activity card rendering and payload exclusion. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.