ui starting point
This commit is contained in:
@@ -18,24 +18,14 @@ class AgentState(MessagesState):
|
|||||||
"""
|
"""
|
||||||
Here we define the state of the agent
|
Here we define the state of the agent
|
||||||
|
|
||||||
In this instance, we're inheriting from CopilotKitState, which will bring in
|
In this instance, we're inheriting from MessagesState, which will bring in
|
||||||
the CopilotKitState fields. We're also adding a custom field, `language`,
|
the messages field for conversation history.
|
||||||
which will be used to set the language of the agent.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proverbs: List[str]
|
|
||||||
tools: List[Any]
|
tools: List[Any]
|
||||||
# your_custom_agent_state: str = ""
|
# your_custom_agent_state: str = ""
|
||||||
|
|
||||||
|
|
||||||
@tool
|
|
||||||
def get_weather(location: str):
|
|
||||||
"""
|
|
||||||
Get the weather for a given location.
|
|
||||||
"""
|
|
||||||
return f"The weather for {location} is 70 degrees."
|
|
||||||
|
|
||||||
|
|
||||||
# @tool
|
# @tool
|
||||||
# def your_tool_here(your_arg: str):
|
# def your_tool_here(your_arg: str):
|
||||||
# """Your tool description here."""
|
# """Your tool description here."""
|
||||||
@@ -43,7 +33,6 @@ def get_weather(location: str):
|
|||||||
# return "Your tool response here."
|
# return "Your tool response here."
|
||||||
|
|
||||||
backend_tools = [
|
backend_tools = [
|
||||||
get_weather
|
|
||||||
# your_tool_here
|
# your_tool_here
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -81,7 +70,7 @@ async def chat_node(state: AgentState, config: RunnableConfig) -> Command[str]:
|
|||||||
|
|
||||||
# 3. Define the system message by which the chat model will be run
|
# 3. Define the system message by which the chat model will be run
|
||||||
system_message = SystemMessage(
|
system_message = SystemMessage(
|
||||||
content=f"You are a helpful assistant. The current proverbs are {state.get('proverbs', [])}."
|
content="You are a helpful assistant."
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Run the model to generate a response
|
# 4. Run the model to generate a response
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCoAgent, useCopilotAction } from "@copilotkit/react-core";
|
import { useCopilotAction } from "@copilotkit/react-core";
|
||||||
import { CopilotKitCSSProperties, CopilotChat } from "@copilotkit/react-ui";
|
import { CopilotKitCSSProperties, CopilotChat } from "@copilotkit/react-ui";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function CopilotKitPage() {
|
export default function CopilotKitPage() {
|
||||||
const [themeColor, setThemeColor] = useState("#6366f1");
|
const [themeColor, setThemeColor] = useState("#6366f1");
|
||||||
|
|
||||||
// 🪁 Frontend Actions: https://docs.copilotkit.ai/guides/frontend-actions
|
|
||||||
useCopilotAction({
|
useCopilotAction({
|
||||||
name: "setThemeColor",
|
name: "setThemeColor",
|
||||||
parameters: [{
|
parameters: [{
|
||||||
name: "themeColor",
|
name: "themeColor",
|
||||||
description: "The theme color to set. Make sure to pick nice colors.",
|
description: "The theme color to set. Make sure to pick nice colors.",
|
||||||
required: true,
|
required: true,
|
||||||
}],
|
}],
|
||||||
handler({ themeColor }) {
|
handler({ themeColor }) {
|
||||||
setThemeColor(themeColor);
|
setThemeColor(themeColor);
|
||||||
@@ -21,150 +20,20 @@ export default function CopilotKitPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ "--copilot-kit-primary-color": themeColor } as CopilotKitCSSProperties}>
|
<main
|
||||||
<YourMainContent themeColor={themeColor} />
|
style={{ "--copilot-kit-primary-color": themeColor } as CopilotKitCSSProperties}
|
||||||
<CopilotChat
|
className="h-screen w-screen flex justify-center bg-gray-50 py-8 px-2"
|
||||||
instructions={"You assist with looking up any relevant information to caving. This includes but is not limited to Cave Locations, Cave Surveying, Cave History."}
|
>
|
||||||
labels={{
|
<div className="h-full w-full max-w-5xl flex flex-col">
|
||||||
title: "AI Cartwright",
|
<CopilotChat
|
||||||
initial: "Would you like to lookup a cave location today?",
|
instructions={"You assist with looking up any relevant information to caving. This includes but is not limited to Cave Locations, Cave Surveying, Cave History."}
|
||||||
}}
|
labels={{
|
||||||
/>
|
title: "AI Cartwright",
|
||||||
|
initial: "Would you like to lookup a cave location today?",
|
||||||
|
}}
|
||||||
|
className="h-full w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// State of the agent, make sure this aligns with your agent's state.
|
|
||||||
type AgentState = {
|
|
||||||
proverbs: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function YourMainContent({ themeColor }: { themeColor: string }) {
|
|
||||||
// 🪁 Shared State: https://docs.copilotkit.ai/coagents/shared-state
|
|
||||||
const { state, setState } = useCoAgent<AgentState>({
|
|
||||||
name: "sample_agent",
|
|
||||||
initialState: {
|
|
||||||
proverbs: [
|
|
||||||
"CopilotKit may be new, but its the best thing since sliced bread.",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// 🪁 Frontend Actions: https://docs.copilotkit.ai/coagents/frontend-actions
|
|
||||||
useCopilotAction({
|
|
||||||
name: "addProverb",
|
|
||||||
parameters: [{
|
|
||||||
name: "proverb",
|
|
||||||
description: "The proverb to add. Make it witty, short and concise.",
|
|
||||||
required: true,
|
|
||||||
}],
|
|
||||||
handler: ({ proverb }) => {
|
|
||||||
setState({
|
|
||||||
...state,
|
|
||||||
proverbs: [...(state.proverbs || []), proverb],
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
//🪁 Generative UI: https://docs.copilotkit.ai/coagents/generative-ui
|
|
||||||
useCopilotAction({
|
|
||||||
name: "get_weather",
|
|
||||||
description: "Get the weather for a given location.",
|
|
||||||
available: "disabled",
|
|
||||||
parameters: [
|
|
||||||
{ name: "location", type: "string", required: true },
|
|
||||||
],
|
|
||||||
render: ({ args }) => {
|
|
||||||
return <WeatherCard location={args.location} themeColor={themeColor} />
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{ backgroundColor: themeColor }}
|
|
||||||
className="h-screen w-screen flex justify-center items-center flex-col transition-colors duration-300"
|
|
||||||
>
|
|
||||||
<div className="bg-white/20 backdrop-blur-md p-8 rounded-2xl shadow-xl max-w-2xl w-full">
|
|
||||||
<h1 className="text-4xl font-bold text-white mb-2 text-center">Proverbs</h1>
|
|
||||||
<p className="text-gray-200 text-center italic mb-6">This is a demonstrative page, but it could be anything you want! 🪁</p>
|
|
||||||
<hr className="border-white/20 my-6" />
|
|
||||||
<div className="flex flex-col gap-3">
|
|
||||||
{state.proverbs?.map((proverb, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="bg-white/15 p-4 rounded-xl text-white relative group hover:bg-white/20 transition-all"
|
|
||||||
>
|
|
||||||
<p className="pr-8">{proverb}</p>
|
|
||||||
<button
|
|
||||||
onClick={() => setState({
|
|
||||||
...state,
|
|
||||||
proverbs: (state.proverbs || []).filter((_, i) => i !== index),
|
|
||||||
})}
|
|
||||||
className="absolute right-3 top-3 opacity-0 group-hover:opacity-100 transition-opacity
|
|
||||||
bg-red-500 hover:bg-red-600 text-white rounded-full h-6 w-6 flex items-center justify-center"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{state.proverbs?.length === 0 && <p className="text-center text-white/80 italic my-8">
|
|
||||||
No proverbs yet. Ask the assistant to add some!
|
|
||||||
</p>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple sun icon for the weather card
|
|
||||||
function SunIcon() {
|
|
||||||
return (
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-14 h-14 text-yellow-200">
|
|
||||||
<circle cx="12" cy="12" r="5" />
|
|
||||||
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" strokeWidth="2" stroke="currentColor" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weather card component where the location and themeColor are based on what the agent
|
|
||||||
// sets via tool calls.
|
|
||||||
function WeatherCard({ location, themeColor }: { location?: string, themeColor: string }) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{ backgroundColor: themeColor }}
|
|
||||||
className="rounded-xl shadow-xl mt-6 mb-4 max-w-md w-full"
|
|
||||||
>
|
|
||||||
<div className="bg-white/20 p-4 w-full">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<h3 className="text-xl font-bold text-white capitalize">{location}</h3>
|
|
||||||
<p className="text-white">Current Weather</p>
|
|
||||||
</div>
|
|
||||||
<SunIcon />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4 flex items-end justify-between">
|
|
||||||
<div className="text-3xl font-bold text-white">70°</div>
|
|
||||||
<div className="text-sm text-white">Clear skies</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-4 pt-4 border-t border-white">
|
|
||||||
<div className="grid grid-cols-3 gap-2 text-center">
|
|
||||||
<div>
|
|
||||||
<p className="text-white text-xs">Humidity</p>
|
|
||||||
<p className="text-white font-medium">45%</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-white text-xs">Wind</p>
|
|
||||||
<p className="text-white font-medium">5 mph</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p className="text-white text-xs">Feels Like</p>
|
|
||||||
<p className="text-white font-medium">72°</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user