);
}
export const EditAgentSchema = z.object({
name: z.string({ required_error: "Name is required" }).min(1, "Name is required"),
persona: z
.string({ required_error: "Personality is required" })
.min(1, "Personality is required"),
color: z.string({ required_error: "Color is required" }).min(1, "Color is required"),
icon: z.string({ required_error: "Icon is required" }).min(1, "Icon is required"),
privacy_level: z
.string({ required_error: "Privacy level is required" })
.min(1, "Privacy level is required"),
chat_model: z
.string({ required_error: "Chat model is required" })
.min(1, "Chat model is required"),
files: z.array(z.string()).default([]).optional(),
input_tools: z.array(z.string()).default([]).optional(),
output_modes: z.array(z.string()).default([]).optional(),
});
interface AgentCardProps {
data: AgentData;
userProfile: UserProfile | null;
isMobileWidth: boolean;
editCard: boolean;
showChatButton?: boolean;
filesOptions: string[];
modelOptions: ModelOptions[];
selectedChatModelOption: string;
isSubscribed: boolean;
setAgentChangeTriggered: (value: boolean) => void;
agentSlug: string;
inputToolOptions: { [key: string]: string };
outputModeOptions: { [key: string]: string };
}
export function AgentCard(props: AgentCardProps) {
const [showModal, setShowModal] = useState(props.agentSlug === props.data.slug);
const [showLoginPrompt, setShowLoginPrompt] = useState(false);
const [errors, setErrors] = useState(null);
let lockIcon = ;
let privacyHoverText = "Private agents are only visible to you.";
if (props.data.privacy_level === "public") {
lockIcon = ;
privacyHoverText = "Public agents are visible to everyone.";
} else if (props.data.privacy_level === "protected") {
lockIcon = ;
privacyHoverText = "Protected agents are visible to anyone with a direct link.";
}
const userData = props.userProfile;
const form = useForm>({
resolver: zodResolver(EditAgentSchema),
defaultValues: {
name: props.data.name,
persona: props.data.persona,
color: props.data.color,
icon: props.data.icon,
privacy_level: props.data.privacy_level,
chat_model: props.data.chat_model,
files: props.data.files,
input_tools: props.data.input_tools,
output_modes: props.data.output_modes,
},
});
useEffect(() => {
form.reset({
name: props.data.name,
persona: props.data.persona,
color: props.data.color,
icon: props.data.icon,
privacy_level: props.data.privacy_level,
chat_model: props.data.chat_model,
files: props.data.files,
input_tools: props.data.input_tools,
output_modes: props.data.output_modes,
});
}, [props.data]);
if (showModal) {
window.history.pushState(
{},
`Khoj AI - Agent ${props.data.slug}`,
`/agents?agent=${props.data.slug}`,
);
}
const onSubmit = (values: z.infer) => {
let agentsApiUrl = `/api/agents`;
let method = props.editCard ? "PATCH" : "POST";
let valuesToSend: any = values;
if (props.editCard) {
valuesToSend = { ...values, slug: props.data.slug };
}
fetch(agentsApiUrl, {
method: method,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(valuesToSend),
})
.then((response) => {
if (response.status === 200) {
form.reset();
setShowModal(false);
setErrors(null);
props.setAgentChangeTriggered(true);
} else {
response.json().then((data) => {
console.error(data);
form.clearErrors();
if (data.error) {
setErrors(data.error);
}
});
}
})
.catch((error) => {
console.error("Error:", error);
setErrors(error);
form.clearErrors();
});
};
const stylingString = convertColorToTextClass(props.data.color);
function makeBadgeFooter() {
return (
{props.editCard && (
)}
{props.data.files && props.data.files.length > 0 && (
}
text={`knowledge`}
hoverText={`The agent has a custom knowledge base with ${props.data.files.length} documents. It can use them to give you answers.`}
/>
)}
}
text={props.data.chat_model}
hoverText={`The agent uses the ${props.data.chat_model} model to chat with you.`}
/>
{props.data.output_modes.map((outputMode) => (
))}
{props.data.input_tools.map((inputTool) => (
))}
Private: only visible to you.
Protected: visible to anyone with a link.
Public: visible to everyone.
All public agents will be reviewed by us before they are
launched.
)}
/>
);
case "color":
return (
(
Color
)}
/>
);
case "icon":
return (
(
Icon
)}
/>
);
case "persona":
return (
(
Personality
What is the personality, thought process, or tuning of this
agent? Get creative; this is how you can influence the agent
constitution.
)}
/>
);
case "files":
return (
(
Knowledge Base
Which information should be part of its digital brain?{" "}
Manage data.
{field.value && field.value.length > 0
? `${field.value.length} files selected`
: "Select files"}
Alert
{warning || error}
{
setWarning(null);
setError(null);
setUploading(false);
}}
>
Close