|
1 | | -# CopilotKit - Streaming JSON Parser + UI Renderer |
| 1 | +# Hashbrown + CopilotKit Starter Template |
2 | 2 |
|
3 | | -I have been working on a new streaming JSON parser that manages its state within React. It preserves object identities while parsing chunks, allowing for fine-grained reactivity and improved UI performance. |
| 3 | +This repo is a starter for exploring how to stream structured model output into React UIs using Hashbrown, then wire that flow through CopilotKit + a LangGraph agent. |
4 | 4 |
|
5 | | -This repository demos using this new streaming JSON parser along with a JSON UI renderer to let an LLM build a dynamic user interface from a fixed set of React components. It uses CopilotKit to build a user interface on top of a LangGraph agent. |
| 5 | +You can use it as a playground for: |
6 | 6 |
|
7 | | -## Getting Started |
| 7 | +- Streaming JSON parsing |
| 8 | +- Streaming markdown with Magic Text |
| 9 | +- Defining UI kits the model can render |
| 10 | +- Exposing UI kit schemas to CopilotKit/agent runtime |
| 11 | + |
| 12 | +## Quick Start |
8 | 13 |
|
9 | 14 | ### Prerequisites |
10 | 15 |
|
11 | | -- Node.js |
12 | | -- pnpm |
13 | | -- Python 3 (for the LangGraph agent) |
| 16 | +- Node.js 20+ |
| 17 | +- npm (or pnpm) |
| 18 | +- Python 3.11+ (for the LangGraph agent) |
14 | 19 |
|
15 | 20 | ### Setup |
16 | 21 |
|
17 | | -Create a `.env` file in `./agent` with an OpenAI API key: |
| 22 | +Set your OpenAI key for the agent in `agent/.env`: |
18 | 23 |
|
19 | | -```sh |
| 24 | +```bash |
20 | 25 | OPENAI_API_KEY=... |
21 | 26 | ``` |
22 | 27 |
|
23 | 28 | Install dependencies: |
24 | 29 |
|
25 | | -```sh |
26 | | -pnpm install |
| 30 | +```bash |
| 31 | +npm install |
27 | 32 | ``` |
28 | 33 |
|
29 | | -Start the dev server: |
| 34 | +Run UI + agent together: |
30 | 35 |
|
31 | | -```sh |
32 | | -pnpm dev |
| 36 | +```bash |
| 37 | +npm run dev |
33 | 38 | ``` |
34 | 39 |
|
35 | | -## Relevant Code Paths |
| 40 | +App URL: `http://localhost:3000` |
| 41 | + |
| 42 | +## What To Explore |
| 43 | + |
| 44 | +### JSON Parser |
| 45 | + |
| 46 | +The parser demos show chunk-by-chunk JSON parsing with live resolved values. |
| 47 | + |
| 48 | +- Demo page: `src/app/parser/page.tsx` |
| 49 | +- AST visualization: `src/app/ast/page.tsx` |
| 50 | +- Chat renderer parser usage: `src/components/custom-message-renderer.tsx` |
| 51 | + - Uses `useJsonParser(message.content ?? "", kit.schema)` to parse streaming assistant output. |
| 52 | + |
| 53 | +Routes: |
| 54 | + |
| 55 | +- `/parser` |
| 56 | +- `/ast` |
| 57 | + |
| 58 | +### Magic Text |
| 59 | + |
| 60 | +Magic Text renders streamed markdown while text is still arriving. |
| 61 | + |
| 62 | +- Demo page: `src/app/magic-text/page.tsx` |
| 63 | + - Uses `<MagicTextRenderer>{markdownSlice}</MagicTextRenderer>` |
| 64 | +- Also visible in composed UI output styling in: |
| 65 | + - `src/app/ui-renderer/page.tsx` |
| 66 | + - `src/components/custom-message-renderer.tsx` |
| 67 | + |
| 68 | +Route: |
| 69 | + |
| 70 | +- `/magic-text` |
| 71 | + |
| 72 | +### UI Kits |
| 73 | + |
| 74 | +The UI kit defines what components the model is allowed to emit. |
| 75 | + |
| 76 | +- UI kit definition: `src/components/chat/chat-kit.tsx` |
| 77 | + - `useUiKit(...)` |
| 78 | + - `exposeMarkdown()` |
| 79 | + - `exposeComponent(WeatherCard, { ...props })` |
| 80 | +- Weather component used by the kit: `src/components/weather.tsx` |
| 81 | + |
| 82 | +Route to test parsed JSON -> rendered components: |
| 83 | + |
| 84 | +- `/ui-renderer` |
| 85 | + |
| 86 | +### Exposing UI Kits To CopilotKit |
| 87 | + |
| 88 | +The flow is: |
| 89 | + |
| 90 | +1. Build schema from the Hashbrown UI kit in the frontend. |
| 91 | +2. Pass schema via CopilotKit runtime context. |
| 92 | +3. Read schema in the agent and enforce structured output. |
| 93 | + |
| 94 | +Code references: |
| 95 | + |
| 96 | +- Frontend context wiring: `src/app/page.tsx` |
| 97 | + - `const chatKit = useChatKit()` |
| 98 | + - `useAgentContext({ description: "output_schema", value: s.toJsonSchema(chatKit.schema) })` |
| 99 | +- CopilotKit runtime endpoint: `src/app/api/copilotkit/route.ts` |
| 100 | + - Registers `sample_agent` with `LangGraphAgent`. |
| 101 | +- Agent schema consumption: `agent/main.py` |
| 102 | + - `apply_structured_output_schema(...)` |
| 103 | + - Applies `ProviderStrategy(schema=schema, strict=True)` when `output_schema` is present. |
36 | 104 |
|
37 | | -- `./src/components/chat/chat-kit.tsx` -> Builds a UI kit of React components that the LLM can use when generating a response. |
| 105 | +Route: |
38 | 106 |
|
39 | | -- `./src/app/page.tsx` -> Derives JSON schema from the UI kit and forwards it to the agent using `useCopilotReadable` |
| 107 | +- `/` (chat experience) |
40 | 108 |
|
41 | | -- `./agent/main.py` -> Reads the schema from `useCopilotReadable` and applies it as a structured output. |
| 109 | +## Project Map |
42 | 110 |
|
43 | | -- `./src/components/custom-message-renderer.tsx` -> Parses the streaming JSON and renders it into a user interface |
| 111 | +- `src/app/page.tsx`: Main chat page (CopilotKit + custom renderer) |
| 112 | +- `src/components/custom-message-renderer.tsx`: Streaming parse + kit rendering |
| 113 | +- `src/components/chat/chat-kit.tsx`: Hashbrown UI kit and exposed components |
| 114 | +- `src/app/parser/page.tsx`: JSON parser playground |
| 115 | +- `src/app/ast/page.tsx`: Parser AST playground |
| 116 | +- `src/app/magic-text/page.tsx`: Magic Text playground |
| 117 | +- `src/app/ui-renderer/page.tsx`: JSON-to-UI renderer playground |
| 118 | +- `src/app/api/copilotkit/route.ts`: CopilotKit runtime API route |
| 119 | +- `agent/main.py`: LangGraph agent, tools, and structured output middleware |
44 | 120 |
|
45 | 121 | ## Troubleshooting |
46 | 122 |
|
47 | | -- If the agent fails to start, confirm your Python environment can install the agent dependencies in `./agent`. |
48 | | -- If you see missing API key errors, double-check that `OPENAI_API_KEY` is present in `./agent/.env`. |
| 123 | +- If the agent does not start, run `npm run install:agent` and confirm Python tooling is available. |
| 124 | +- If API calls fail, verify `agent/.env` contains `OPENAI_API_KEY`. |
| 125 | +- If chat cannot reach the agent, confirm LangGraph is running on `http://localhost:8123` (default in `src/app/api/copilotkit/route.ts`). |
0 commit comments