Skip to content

Commit

Permalink
chore: prep for tool workflow update
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanhopperlowe committed Nov 1, 2024
1 parent 0028e85 commit 8773440
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 120 deletions.
10 changes: 6 additions & 4 deletions ui/admin/app/components/TruncatedText.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { cn } from "~/lib/utils";

import { TypographyP } from "~/components/Typography";
import {
Tooltip,
Expand All @@ -8,16 +10,16 @@ import {

export function TruncatedText({
content,
maxWidth,
className,
}: {
content: string;
maxWidth: string;
content: React.ReactNode;
className?: string;
}) {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div className={`${maxWidth} truncate cursor-pointer`}>
<div className={cn(`truncate cursor-pointer`, className)}>
<TypographyP className="truncate">
{content}
</TypographyP>
Expand Down
51 changes: 51 additions & 0 deletions ui/admin/app/components/Typography.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { VariantProps, cva } from "class-variance-authority";
import React, { ReactNode } from "react";

import { cn } from "~/lib/utils";
Expand Down Expand Up @@ -182,3 +183,53 @@ export function TypographyMuted({
</p>
);
}

const typographyVariants = cva(`scroll-m-20`, {
variants: {
variant: {
h1: `text-4xl font-extrabold tracking-tight lg:text-5xl`,
h2: `text-3xl font-semibold tracking-tight first:mt-0`,
h3: `text-2xl font-semibold tracking-tight`,
h4: `text-xl font-semibold tracking-tight`,
p: `leading-7`,
blockquote: `mt-6 border-l-2 pl-6 italic`,
inlineCode: `relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold`,
lead: `text-xl text-muted-foreground`,
large: `text-lg font-semibold`,
small: `text-sm font-medium leading-none`,
muted: `text-sm text-muted-foreground`,
},
},
defaultVariants: {
variant: `p`,
},
});

const componentMap: Record<
Required<VariantProps<typeof typographyVariants>>["variant"],
TypographyElement
> = {
h1: `h1`,
h2: `h2`,
h3: `h3`,
h4: `h4`,
p: `p`,
blockquote: `blockquote`,
inlineCode: `code`,
lead: `p`,
large: `div`,
small: `small`,
muted: `p`,
};

export function Typography({
variant,
className,
...props
}: TypographyProps<TypographyElement> &
VariantProps<typeof typographyVariants>) {
return React.createElement(variantConfig, {
className: cn(variantConfig, className),
...props,
});
}
30 changes: 29 additions & 1 deletion ui/admin/app/components/agent/Agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,18 @@ function AgentContent({ className, onRefresh }: AgentProps) {
<WrenchIcon className="w-5 h-5" />
Tools
</span>

<TypographyP className="text-muted-foreground flex items-center gap-2">
Add tools the allow the agent to perform useful actions
such as searching the web, reading files, or interacting
with other systems.
</TypographyP>

<ToolForm
agent={agentUpdates}
onChange={debouncedSetAgentInfo}
onChange={({ tools }) =>
debouncedSetAgentInfo(convertTools(tools))
}
/>
</div>

Expand Down Expand Up @@ -122,3 +126,27 @@ function AgentContent({ className, onRefresh }: AgentProps) {
</div>
);
}
function convertTools(
tools: { tool: string; variant: "fixed" | "default" | "available" }[]
) {
type ToolObj = Pick<
AgentType,
"tools" | "defaultThreadTools" | "availableThreadTools"
>;

return tools.reduce(
(acc, { tool, variant }) => {
if (variant === "fixed") acc.tools?.push(tool);
else if (variant === "default") acc.defaultThreadTools?.push(tool);
else if (variant === "available")
acc.availableThreadTools?.push(tool);

return acc;
},
{
tools: [],
defaultThreadTools: [],
availableThreadTools: [],
} as ToolObj
);
}
121 changes: 99 additions & 22 deletions ui/admin/app/components/agent/ToolEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { TrashIcon } from "lucide-react";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import useSWR from "swr";
import { z } from "zod";

import { ToolReferenceService } from "~/lib/service/api/toolreferenceService";
import { noop } from "~/lib/utils";

import { ToolIcon } from "~/components/tools/ToolIcon";
import { LoadingSpinner } from "~/components/ui/LoadingSpinner";
import { Button } from "~/components/ui/button";
import { TruncatedText } from "../TruncatedText";
import { ToolIcon } from "../tools/ToolIcon";
import { LoadingSpinner } from "../ui/LoadingSpinner";
import { Button } from "../ui/button";
import { Form, FormField, FormItem, FormMessage } from "../ui/form";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";

export function ToolEntry({
tool,
Expand All @@ -22,26 +36,89 @@ export function ToolEntry({

return (
<div className="flex items-center space-x-2 justify-between mt-1">
<div className="border text-sm px-3 shadow-sm rounded-md p-2 w-full flex items-center gap-2">
{isLoading ? (
<LoadingSpinner className="w-4 h-4" />
) : (
<ToolIcon
className="w-4 h-4"
name={toolReference?.name || tool}
icon={toolReference?.metadata?.icon}
/>
)}
{toolReference?.name || tool}
<div className="border text-sm px-3 shadow-sm rounded-md p-2 w-full flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
{isLoading ? (
<LoadingSpinner className="w-5 h-5" />
) : (
<ToolIcon
className="w-5 h-5"
name={toolReference?.name || tool}
icon={toolReference?.metadata?.icon}
/>
)}

<TruncatedText content={toolReference?.name || tool} />
</div>

<div className="flex items-center gap-2">
<ToolEntryForm onChange={noop} />

<Button
type="button"
variant="secondary"
size="icon"
onClick={() => onDelete()}
>
<TrashIcon className="w-5 h-5" />
</Button>
</div>
</div>
<Button
type="button"
variant="secondary"
size="icon"
onClick={() => onDelete()}
>
<TrashIcon className="w-4 h-4" />
</Button>
</div>
);
}

const schema = z.object({
variant: z.enum(["fixed", "default", "canAdd"]),
});

type ToolEntryForm = z.infer<typeof schema>;

function ToolEntryForm({
onChange,
}: {
onChange: (data: ToolEntryForm) => void;
}) {
const form = useForm<ToolEntryForm>({
resolver: zodResolver(schema),
defaultValues: {
variant: "default",
},
});

useEffect(() => {
return form.watch((values) => {
const { success, data } = schema.safeParse(values);

if (!success) return;

onChange(data);
}).unsubscribe;
}, [form, onChange]);

return (
<Form {...form}>
<FormField
control={form.control}
name="variant"
render={({ field: { ref: _, ...field } }) => (
<FormItem>
<Select {...field} onValueChange={field.onChange}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>

<SelectContent>
<SelectItem value="fixed">Fixed</SelectItem>
<SelectItem value="default">Default</SelectItem>
<SelectItem value="canAdd">Can Add</SelectItem>
</SelectContent>
</Select>

<FormMessage />
</FormItem>
)}
/>
</Form>
);
}
Loading

0 comments on commit 8773440

Please sign in to comment.