Skip to content

Commit 25ee60e

Browse files
committed
feat: add shared showcase packages with tools, components, and test coverage
- @copilotkit/showcase-shared: React hooks, components, A2UI catalog, SalesDashboard - Shared Python tools: 7 implementations + 54 pytest tests - Shared TypeScript tools: equivalents + 43 vitest tests - React component tests: 68 tests (7 suites) - Aimock fixtures: 18 deterministic demo scenarios
1 parent 0ed497d commit 25ee60e

65 files changed

Lines changed: 4939 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ packages:
99
- "examples/showcases/generative-ui-playground"
1010
- "!examples/v1/_legacy"
1111
- "showcase/scripts"
12+
- "showcase/shared/frontend"
1213
onlyBuiltDependencies:
1314
- better-sqlite3

showcase/shared/feature-registry.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,30 @@
332332
"name": "vNext Chat",
333333
"category": "platform",
334334
"description": "Experimental next-generation chat using CopilotKit vNext runtime"
335+
},
336+
{
337+
"id": "shared-state",
338+
"name": "Shared State",
339+
"category": "agent-state",
340+
"description": "Bidirectional state sharing between agent and UI"
341+
},
342+
{
343+
"id": "controlled-gen-ui",
344+
"name": "Controlled Generative UI",
345+
"category": "generative-ui",
346+
"description": "Controlled generative UI rendering from agent"
347+
},
348+
{
349+
"id": "a2ui",
350+
"name": "A2UI",
351+
"category": "a2ui",
352+
"description": "Agent-to-UI protocol rendering"
353+
},
354+
{
355+
"id": "frontend-tools",
356+
"name": "Frontend Tools",
357+
"category": "interactivity",
358+
"description": "Frontend tool execution triggered by the agent"
335359
}
336360
]
337361
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "@copilotkit/showcase-shared",
3+
"version": "0.0.1",
4+
"private": true,
5+
"main": "src/index.ts",
6+
"types": "src/index.ts",
7+
"scripts": {},
8+
"dependencies": {
9+
"recharts": "^2.15.0",
10+
"zod": "^3.24.0"
11+
},
12+
"devDependencies": {
13+
"@testing-library/jest-dom": "^6.9.1",
14+
"@testing-library/react": "^16.3.2",
15+
"@types/react": "^19.0.0",
16+
"@types/react-dom": "^19.0.0",
17+
"jsdom": "^29.0.2",
18+
"typescript": "^5.0.0"
19+
},
20+
"peerDependencies": {
21+
"@copilotkit/a2ui-renderer": "*",
22+
"@copilotkit/react-core": "*",
23+
"react": "^19.0.0",
24+
"react-dom": "^19.0.0"
25+
}
26+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* Demonstration Catalog -- Component Definitions
3+
*
4+
* Platform-agnostic definitions: component names, props (Zod), descriptions.
5+
* This is the contract between the app and the AI agent. Agents receive these
6+
* definitions as context so they know what components are available.
7+
*
8+
* Renderers (React, React Native, etc.) import these definitions and provide
9+
* platform-specific implementations, type-checked against the Zod schemas.
10+
*/
11+
12+
import { z } from "zod";
13+
14+
/**
15+
* Dynamic string: accepts either a literal string or a data-model path binding
16+
* like `{ path: "airline" }`. The GenericBinder resolves path bindings to the
17+
* actual value at render time.
18+
*/
19+
const DynString = z.union([z.string(), z.object({ path: z.string() })]);
20+
21+
export const demonstrationCatalogDefinitions = {
22+
Title: {
23+
description: "A heading. Use for section titles and page headers.",
24+
props: z.object({
25+
text: z.string(),
26+
level: z.string().optional(),
27+
}),
28+
},
29+
30+
// Text: removed -- the basic catalog's Text uses DynamicStringSchema
31+
// which supports path bindings (e.g. { path: "flights[*].airline" }).
32+
// Overriding it with z.string() breaks fixed-schema data binding.
33+
34+
Row: {
35+
description: "Horizontal layout container.",
36+
props: z.object({
37+
gap: z.number().optional(),
38+
align: z.string().optional(),
39+
justify: z.string().optional(),
40+
// Union with { componentId, path } so GenericBinder treats this as
41+
// STRUCTURAL and resolves template children from the data model.
42+
children: z.union([
43+
z.array(z.string()),
44+
z.object({ componentId: z.string(), path: z.string() }),
45+
]),
46+
}),
47+
},
48+
49+
Column: {
50+
description: "Vertical layout container.",
51+
props: z.object({
52+
gap: z.number().optional(),
53+
align: z.string().optional(),
54+
// Same union as Row -- required for template children support.
55+
children: z.union([
56+
z.array(z.string()),
57+
z.object({ componentId: z.string(), path: z.string() }),
58+
]),
59+
}),
60+
},
61+
62+
DashboardCard: {
63+
description:
64+
"A card container with title and optional subtitle. Has a 'child' slot for content (chart, metrics, etc). Use 'child' with a single component ID.",
65+
props: z.object({
66+
title: z.string(),
67+
subtitle: z.string().optional(),
68+
child: z.string().optional(),
69+
}),
70+
},
71+
72+
Metric: {
73+
description:
74+
"A key metric display with label, value, and optional trend indicator. Great for KPIs and stats.",
75+
props: z.object({
76+
label: z.string(),
77+
value: z.string(),
78+
trend: z.enum(["up", "down", "neutral"]).optional(),
79+
trendValue: z.string().optional(),
80+
}),
81+
},
82+
83+
PieChart: {
84+
description:
85+
"A pie/donut chart. Provide data as array of {label, value, color} objects.",
86+
props: z.object({
87+
data: z.array(
88+
z.object({
89+
label: z.string(),
90+
value: z.number(),
91+
color: z.string().optional(),
92+
}),
93+
),
94+
innerRadius: z.number().optional(),
95+
}),
96+
},
97+
98+
BarChart: {
99+
description:
100+
"A bar chart. Provide data as array of {label, value} objects.",
101+
props: z.object({
102+
data: z.array(z.object({ label: z.string(), value: z.number() })),
103+
color: z.string().optional(),
104+
}),
105+
},
106+
107+
Badge: {
108+
description:
109+
"A small status badge/tag. Use for labels, statuses, categories.",
110+
props: z.object({
111+
text: z.string(),
112+
variant: z
113+
.enum(["success", "warning", "error", "info", "neutral"])
114+
.optional(),
115+
}),
116+
},
117+
118+
DataTable: {
119+
description: "A data table with columns and rows.",
120+
props: z.object({
121+
columns: z.array(z.object({ key: z.string(), label: z.string() })),
122+
rows: z.array(z.record(z.any())),
123+
}),
124+
},
125+
126+
Button: {
127+
description:
128+
"An interactive button with an action event. Use 'child' with a Text component ID for the label. 'action' is dispatched on click.",
129+
props: z.object({
130+
child: z
131+
.string()
132+
.describe(
133+
"The ID of the child component (e.g. a Text component for the label).",
134+
),
135+
variant: z.enum(["primary", "secondary", "ghost"]).optional(),
136+
// Union with { event } so GenericBinder resolves this as ACTION -> callable () => void.
137+
action: z
138+
.union([
139+
z.object({
140+
event: z.object({
141+
name: z.string(),
142+
context: z.record(z.any()).optional(),
143+
}),
144+
}),
145+
z.null(),
146+
])
147+
.optional(),
148+
}),
149+
},
150+
151+
FlightCard: {
152+
description:
153+
"A rich flight result card. Displays airline, flight number, route, times, duration, status, and price. Use inside a Row for side-by-side layout.",
154+
props: z.object({
155+
airline: DynString,
156+
airlineLogo: DynString,
157+
flightNumber: DynString,
158+
origin: DynString,
159+
destination: DynString,
160+
date: DynString,
161+
departureTime: DynString,
162+
arrivalTime: DynString,
163+
duration: DynString,
164+
status: DynString,
165+
statusColor: DynString.optional(),
166+
price: DynString,
167+
action: z
168+
.union([
169+
z.object({
170+
event: z.object({
171+
name: z.string(),
172+
context: z.record(z.any()).optional(),
173+
}),
174+
}),
175+
z.null(),
176+
])
177+
.optional(),
178+
}),
179+
},
180+
};
181+
182+
/** Type helper for renderers */
183+
export type DemonstrationCatalogDefinitions =
184+
typeof demonstrationCatalogDefinitions;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
{
3+
"id": "root",
4+
"component": "Row",
5+
"children": {
6+
"componentId": "flight-card",
7+
"path": "/flights"
8+
},
9+
"gap": 16
10+
},
11+
{
12+
"id": "flight-card",
13+
"component": "FlightCard",
14+
"airline": { "path": "airline" },
15+
"airlineLogo": { "path": "airlineLogo" },
16+
"flightNumber": { "path": "flightNumber" },
17+
"origin": { "path": "origin" },
18+
"destination": { "path": "destination" },
19+
"date": { "path": "date" },
20+
"departureTime": { "path": "departureTime" },
21+
"arrivalTime": { "path": "arrivalTime" },
22+
"duration": { "path": "duration" },
23+
"status": { "path": "status" },
24+
"price": { "path": "price" },
25+
"action": {
26+
"event": {
27+
"name": "book_flight",
28+
"context": {
29+
"flightNumber": { "path": "flightNumber" },
30+
"origin": { "path": "origin" },
31+
"destination": { "path": "destination" },
32+
"price": { "path": "price" }
33+
}
34+
}
35+
}
36+
}
37+
]

0 commit comments

Comments
 (0)