Skip to content

Commit 6da5393

Browse files
mmeranst91maxkorp
authored
Improve Dojo examples (#197)
* Optimize Dojo example code to simple and "idiomatic" * use CPK branch that fixes tool results * update example to use ToolNode * send tool result * add mastra local tool based gen UI * add mastra tool based gen ui * add agno support * update agno example * remove console.logs * add reasoning example * fix missing quotes * upgrade to the latest agno * regenerate json * fix compile error * align with main * Combine agno examples * Fix agentic chat reasoning example won't start * regenerate files.json * regen again --------- Co-authored-by: ran <[email protected]> Co-authored-by: Max Korp <[email protected]>
1 parent ea290da commit 6da5393

File tree

41 files changed

+6017
-604
lines changed

Some content is hidden

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

41 files changed

+6017
-604
lines changed

typescript-sdk/apps/dojo/scripts/prep-dojo-everything.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const serverStarterAllFeatures = {
4545

4646
// Agno
4747
const agno = {
48-
command: 'uv venv --allow-existing && uv pip install -r requirements.txt',
48+
command: 'uv sync',
4949
name: 'Agno',
5050
cwd: path.join(integrationsRoot, 'agno/examples'),
5151
}

typescript-sdk/apps/dojo/scripts/run-dojo-everything.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const serverStarterAllFeatures = {
4545

4646
// Agno
4747
const agno = {
48-
command: 'uv run agent.py',
48+
command: 'uv run dev',
4949
name: 'Agno',
5050
cwd: path.join(integrationsRoot, 'agno/examples'),
5151
env: {PORT: 8002},

typescript-sdk/apps/dojo/src/agents.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
163163
tool_based_generative_ui: new LangGraphHttpAgent({
164164
url: `${envVars.langgraphFastApiUrl}/agent/tool_based_generative_ui`,
165165
}),
166+
agentic_chat_reasoning: new LangGraphHttpAgent({
167+
url: "http://localhost:8000/agent/agentic_chat_reasoning",
168+
}),
166169
};
167170
},
168171
},
@@ -171,7 +174,10 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
171174
agents: async () => {
172175
return {
173176
agentic_chat: new AgnoAgent({
174-
url: `${envVars.agnoUrl}/agui`,
177+
url: `${envVars.agnoUrl}/agentic_chat/agui`,
178+
}),
179+
tool_based_generative_ui: new AgnoAgent({
180+
url: `${envVars.agnoUrl}/tool_based_generative_ui/agui`,
175181
}),
176182
};
177183
},
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# 🤖 Agentic Chat with Reasoning
2+
3+
## What This Demo Shows
4+
5+
This demo showcases CopilotKit's **agentic chat** capabilities with **frontend
6+
tool integration**:
7+
8+
1. **Natural Conversation**: Chat with your Copilot in a familiar chat interface
9+
2. **Frontend Tool Execution**: The Copilot can directly interacts with your UI
10+
by calling frontend functions
11+
3. **Seamless Integration**: Tools defined in the frontend and automatically
12+
discovered and made available to the agent
13+
14+
## How to Interact
15+
16+
Try asking your Copilot to:
17+
18+
- "Can you change the background color to something more vibrant?"
19+
- "Make the background a blue to purple gradient"
20+
- "Set the background to a sunset-themed gradient"
21+
- "Change it back to a simple light color"
22+
23+
You can also chat about other topics - the agent will respond conversationally
24+
while having the ability to use your UI tools when appropriate.
25+
26+
## ✨ Frontend Tool Integration in Action
27+
28+
**What's happening technically:**
29+
30+
- The React component defines a frontend function using `useCopilotAction`
31+
- CopilotKit automatically exposes this function to the agent
32+
- When you make a request, the agent determines whether to use the tool
33+
- The agent calls the function with the appropriate parameters
34+
- The UI immediately updates in response
35+
36+
**What you'll see in this demo:**
37+
38+
- The Copilot understands requests to change the background
39+
- It generates CSS values for colors and gradients
40+
- When it calls the tool, the background changes instantly
41+
- The agent provides a conversational response about the changes it made
42+
43+
This technique of exposing frontend functions to your Copilot can be extended to
44+
any UI manipulation you want to enable, from theme changes to data filtering,
45+
navigation, or complex UI state management!
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"use client";
2+
import React, { useState } from "react";
3+
import "@copilotkit/react-ui/styles.css";
4+
import "./style.css";
5+
import { CopilotKit, useCoAgent, useCopilotAction, useCopilotChat } from "@copilotkit/react-core";
6+
import { CopilotChat } from "@copilotkit/react-ui";
7+
import { ChevronDown } from "lucide-react";
8+
import { Button } from "@/components/ui/button";
9+
import {
10+
DropdownMenu,
11+
DropdownMenuContent,
12+
DropdownMenuItem,
13+
DropdownMenuLabel,
14+
DropdownMenuSeparator,
15+
DropdownMenuTrigger,
16+
} from "@/components/ui/dropdown-menu";
17+
18+
interface AgenticChatProps {
19+
params: Promise<{
20+
integrationId: string;
21+
}>;
22+
}
23+
24+
const AgenticChat: React.FC<AgenticChatProps> = ({ params }) => {
25+
const { integrationId } = React.use(params);
26+
27+
return (
28+
<CopilotKit
29+
runtimeUrl={`/api/copilotkit/${integrationId}`}
30+
showDevConsole={false}
31+
// agent lock to the relevant agent
32+
agent="agentic_chat_reasoning"
33+
>
34+
<Chat />
35+
</CopilotKit>
36+
);
37+
};
38+
39+
interface AgentState {
40+
model: string;
41+
}
42+
43+
const Chat = () => {
44+
const [background, setBackground] = useState<string>("--copilot-kit-background-color");
45+
const { state: agentState, setState: setAgentState } = useCoAgent<AgentState>({
46+
name: "agentic_chat_reasoning",
47+
initialState: {
48+
model: "OpenAI",
49+
},
50+
});
51+
52+
// Initialize model if not set
53+
const selectedModel = agentState?.model || "OpenAI";
54+
55+
const handleModelChange = (model: string) => {
56+
setAgentState({ model });
57+
};
58+
59+
useCopilotAction({
60+
name: "change_background",
61+
description:
62+
"Change the background color of the chat. Can be anything that the CSS background attribute accepts. Regular colors, linear of radial gradients etc.",
63+
parameters: [
64+
{
65+
name: "background",
66+
type: "string",
67+
description: "The background. Prefer gradients.",
68+
},
69+
],
70+
handler: ({ background }) => {
71+
setBackground(background);
72+
},
73+
});
74+
75+
return (
76+
<div className="flex flex-col h-full w-full" style={{ background }}>
77+
{/* Reasoning Model Dropdown */}
78+
<div className="h-[65px] border-b border-gray-200 dark:border-gray-700">
79+
<div className="h-full flex items-center justify-center">
80+
<div className="flex items-center gap-2">
81+
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
82+
Reasoning Model:
83+
</span>
84+
<DropdownMenu>
85+
<DropdownMenuTrigger asChild>
86+
<Button variant="outline" className="w-[140px] justify-between">
87+
{selectedModel}
88+
<ChevronDown className="h-4 w-4 opacity-50" />
89+
</Button>
90+
</DropdownMenuTrigger>
91+
<DropdownMenuContent className="w-[140px]">
92+
<DropdownMenuLabel>Select Model</DropdownMenuLabel>
93+
<DropdownMenuSeparator />
94+
<DropdownMenuItem onClick={() => handleModelChange("OpenAI")}>
95+
OpenAI
96+
</DropdownMenuItem>
97+
<DropdownMenuItem onClick={() => handleModelChange("Anthropic")}>
98+
Anthropic
99+
</DropdownMenuItem>
100+
<DropdownMenuItem onClick={() => handleModelChange("Gemini")}>
101+
Gemini
102+
</DropdownMenuItem>
103+
</DropdownMenuContent>
104+
</DropdownMenu>
105+
</div>
106+
</div>
107+
</div>
108+
109+
{/* Chat Container */}
110+
<div className="flex-1 flex justify-center items-center p-4">
111+
<div className="w-8/10 h-full rounded-lg">
112+
<CopilotChat
113+
className="h-full rounded-2xl"
114+
labels={{ initial: "Hi, I'm an agent. Want to chat?" }}
115+
/>
116+
</div>
117+
</div>
118+
</div>
119+
);
120+
};
121+
122+
export default AgenticChat;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.copilotKitInput {
2+
border-bottom-left-radius: 0.75rem;
3+
border-bottom-right-radius: 0.75rem;
4+
border-top-left-radius: 0.75rem;
5+
border-top-right-radius: 0.75rem;
6+
border: 1px solid var(--copilot-kit-separator-color) !important;
7+
}
8+
9+
.copilotKitChat {
10+
background-color: #fff !important;
11+
}
12+

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/tool_based_generative_ui/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ function Haiku() {
291291

292292
useCopilotAction({
293293
name: "generate_haiku",
294+
available: "frontend",
294295
parameters: [
295296
{
296297
name: "japanese",

typescript-sdk/apps/dojo/src/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ export const featureConfig: FeatureConfig[] = [
5353
description: "Use collaboration to edit a document in real time with your Copilot",
5454
tags: ["State", "Streaming", "Tools"],
5555
}),
56+
createFeatureConfig({
57+
id: "agentic_chat_reasoning",
58+
name: "Agentic Chat Reasoning",
59+
description: "Chat with a reasoning Copilot and call frontend tools",
60+
tags: ["Chat", "Tools", "Streaming", "Reasoning"],
61+
}),
5662
];
5763

5864
export default featureConfig;

typescript-sdk/apps/dojo/src/files.json

Lines changed: 65 additions & 19 deletions
Large diffs are not rendered by default.

typescript-sdk/apps/dojo/src/mastra/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { LibSQLStore } from "@mastra/libsql";
55
import { DynamoDBStore } from "@mastra/dynamodb";
66

77
import { Mastra } from "@mastra/core";
8+
import { createTool } from "@mastra/core";
89
import { z } from "zod";
910

1011

@@ -118,5 +119,31 @@ export const mastra = new Mastra({
118119
},
119120
}),
120121
}),
122+
tool_based_generative_ui: new Agent({
123+
name: "tool_based_generative_ui",
124+
instructions: `
125+
You are a helpful assistant for creating haikus.
126+
`,
127+
model: openai("gpt-4o"),
128+
tools: {
129+
generate_haiku: createTool({
130+
id: "generate_haiku",
131+
description:
132+
"Generate a haiku in Japanese and its English translation. Also select exactly 3 relevant images from the provided list based on the haiku's theme.",
133+
inputSchema: z.object({
134+
japanese: z
135+
.array(z.string())
136+
.describe("An array of three lines of the haiku in Japanese"),
137+
english: z
138+
.array(z.string())
139+
.describe("An array of three lines of the haiku in English"),
140+
}),
141+
outputSchema: z.string(),
142+
execute: async ({ context }) => {
143+
return "Haiku generated.";
144+
},
145+
}),
146+
},
147+
}),
121148
},
122149
});

0 commit comments

Comments
 (0)