components/Action.tsx (87 lines of code) (raw):
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { handleTool, ToolName } from "@/lib/tools/tools-handling";
import { useState } from "react";
import { Loader2 } from "lucide-react";
import useConversationStore from "@/stores/useConversationStore";
import { processMessages } from "@/lib/assistant";
export default function Action({
name,
functionName,
parameters,
}: {
name: string;
functionName: ToolName;
parameters: Record<string, any>;
}) {
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const addConversationItem = useConversationStore(
(s) => s.addConversationItem
);
const removeRecommendedAction = useConversationStore(
(s) => s.removeRecommendedAction
);
const handleConfirm = async () => {
setLoading(true);
const result = await handleTool(functionName, parameters, "execute");
if (result.result) {
console.log("Executed function", functionName, parameters, result);
// Add to conversation as a new assistant message
addConversationItem({
role: "assistant",
content: JSON.stringify(result),
});
await processMessages();
} else {
console.log("Error executing function", functionName, parameters, result);
}
setLoading(false);
// Close dialog and remove suggested action
setOpen(false);
removeRecommendedAction(functionName);
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<div className="bg-black hover:bg-zinc-800 text-white px-3 py-1.5 text-sm rounded-lg cursor-pointer">
{name}
</div>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{name}</DialogTitle>
<DialogDescription>
Confirm the action to take to resolve the customer query
</DialogDescription>
<DialogDescription>{functionName}</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
{Object.entries(parameters).map(([key, value]) => (
<div key={key} className="flex gap-2 items-center">
<Label htmlFor={key} className="w-24">
{key}
</Label>
<Input id={key} defaultValue={value} className="col-span-3" />
</div>
))}
</div>
<DialogFooter>
<Button
type="submit"
onClick={() => handleConfirm()}
disabled={loading}
>
{loading ? <Loader2 className="animate-spin" /> : "Confirm"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}