);
}
const agentsFetcher = () =>
window
.fetch("/api/agents")
.then((res) => res.json())
.catch((err) => console.log(err));
// A generic fetcher function that uses the fetch API to make a request to a given URL and returns the response as JSON.
const fetcher = (url: string) => fetch(url).then((res) => res.json());
interface AgentCardProps {
data: AgentData;
userProfile: UserProfile | null;
isMobileWidth: boolean;
editCard: boolean;
filesOptions: string[];
modelOptions: ModelOptions[];
selectedChatModelOption: string;
isSubscribed: boolean;
setAgentChangeTriggered: (value: boolean) => void;
agentSlug: string;
inputToolOptions: { [key: string]: string };
outputModeOptions: { [key: string]: string };
}
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";
fetch(agentsApiUrl, {
method: method,
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
})
.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 it can use 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) => (
))}
Create Agent
{!props.userProfile && showLoginPrompt && (
)}
Dismiss
);
}
return (
);
}
interface AgentConfigurationOptions {
input_tools: { [key: string]: string };
output_modes: { [key: string]: string };
}
export default function Agents() {
const { data, error, mutate } = useSWR("agents", agentsFetcher, {
revalidateOnFocus: false,
});
const authenticatedData = useAuthenticatedData();
const { userConfig } = useUserConfig(true);
const [showLoginPrompt, setShowLoginPrompt] = useState(false);
const isMobileWidth = useIsMobileWidth();
const [personalAgents, setPersonalAgents] = useState([]);
const [publicAgents, setPublicAgents] = useState([]);
const [agentSlug, setAgentSlug] = useState(null);
const { data: filesData, error: fileError } = useSWR(
userConfig ? "/api/content/computer" : null,
fetcher,
);
const { data: agentConfigurationOptions, error: agentConfigurationOptionsError } =
useSWR("/api/agents/options", fetcher);
const [agentChangeTriggered, setAgentChangeTriggered] = useState(false);
useEffect(() => {
if (agentChangeTriggered) {
mutate();
setAgentChangeTriggered(false);
}
}, [agentChangeTriggered]);
useEffect(() => {
if (data) {
const personalAgents = data.filter(
(agent) => agent.creator === authenticatedData?.username,
);
setPersonalAgents(personalAgents);
// Public agents are agents that are not private and not created by the user
const publicAgents = data.filter(
(agent) =>
agent.privacy_level !== "private" &&
agent.creator !== authenticatedData?.username,
);
setPublicAgents(publicAgents);
if (typeof window !== "undefined") {
const searchParams = new URLSearchParams(window.location.search);
const agentSlug = searchParams.get("agent");
// Search for the agent with the slug in the URL
if (agentSlug) {
setAgentSlug(agentSlug);
const selectedAgent = data.find((agent) => agent.slug === agentSlug);
if (!selectedAgent) {
// See if the agent is accessible as a protected agent.
fetch(`/api/agents/${agentSlug}`)
.then((res) => {
if (res.status === 404) {
throw new Error("Agent not found");
}
return res.json();
})
.then((agent: AgentData) => {
if (agent.privacy_level === "protected") {
setPublicAgents((prev) => [...prev, agent]);
}
});
}
}
}
}
}, [data]);
if (error) {
return (
Agents
Error loading agents
);
}
if (!data) {
return (
booting up your agents
);
}
const modelOptions: ModelOptions[] = userConfig?.chat_model_options || [];
const selectedChatModelOption: number = userConfig?.selected_chat_model_config || 0;
const isSubscribed: boolean =
(userConfig?.subscription_state &&
[
SubscriptionStates.SUBSCRIBED.valueOf(),
SubscriptionStates.TRIAL.valueOf(),
SubscriptionStates.UNSUBSCRIBED.valueOf(),
].includes(userConfig.subscription_state)) ||
false;
// The default model option should map to the item in the modelOptions array that has the same id as the selectedChatModelOption
const defaultModelOption = modelOptions.find(
(modelOption) => modelOption.id === selectedChatModelOption,
);
return (
Agents
{showLoginPrompt && (
)}
How it works Use any of these
specialized personas to tune your conversation to your needs.