Skip to content

Commit

Permalink
Merge pull request #593 from ryanhopperlowe/admin/fix/display-for-age…
Browse files Browse the repository at this point in the history
…nt-refname-conflict

feat: admin ui - display information on agent when refName conflict
  • Loading branch information
ryanhopperlowe authored Nov 15, 2024
2 parents 59c0450 + 9c09355 commit 36f9e02
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 54 deletions.
1 change: 1 addition & 0 deletions apiclient/types/assitant.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ type Assistant struct {
Name string `json:"name"`
Description string `json:"description"`
Icons AgentIcons `json:"icons"`
EntityID string `json:"entityID"`
}

type AssistantList List[Assistant]
Expand Down
1 change: 1 addition & 0 deletions pkg/api/handlers/assistants.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func convertAssistant(agent v1.Agent) types.Assistant {
Metadata: MetadataFrom(&agent),
Name: agent.Spec.Manifest.Name,
Description: agent.Spec.Manifest.Description,
EntityID: agent.ObjectMeta.Name,
Icons: icons,
}
assistant.ID = agent.Spec.Manifest.RefName
Expand Down
9 changes: 8 additions & 1 deletion pkg/storage/openapi/generated/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 7 additions & 23 deletions ui/admin/app/components/agent/Agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import { cn } from "~/lib/utils";
import { TypographyH4, TypographyP } from "~/components/Typography";
import { useAgent } from "~/components/agent/AgentContext";
import { AgentForm } from "~/components/agent/AgentForm";
import { AgentPublishStatus } from "~/components/agent/AgentPublishStatus";
import { PastThreads } from "~/components/agent/PastThreads";
import { Publish } from "~/components/agent/Publish";
import { ToolForm } from "~/components/agent/ToolForm";
import { Unpublish } from "~/components/agent/Unpublish";
import { CopyText } from "~/components/composed/CopyText";
import { AgentKnowledgePanel } from "~/components/knowledge";
import { Button } from "~/components/ui/button";
import { Card } from "~/components/ui/card";
Expand Down Expand Up @@ -52,26 +50,11 @@ export function Agent({ className, onRefresh }: AgentProps) {
return (
<div className="h-full flex flex-col">
<ScrollArea className={cn("h-full", className)}>
<div className="flex w-full justify-between px-8 pt-4 items-center gap-4">
{agentUpdates.refName ? (
<CopyText
className="h-8 text-muted-foreground text-sm bg-background flex-row-reverse"
holdStatusDelay={10000}
text={`${window.location.protocol}//${window.location.host}/${agentUpdates.refName}`}
/>
) : (
<div />
)}

{agentUpdates.refName ? (
<Unpublish onChange={debouncedSetAgentInfo} />
) : (
<Publish
agent={agentUpdates}
onChange={debouncedSetAgentInfo}
/>
)}
</div>
<AgentPublishStatus
agent={agentUpdates}
onChange={partialSetAgent}
/>

<Card className="p-4 m-4 lg:mx-6 xl:mx-8">
<AgentForm
agent={agentUpdates}
Expand Down Expand Up @@ -146,6 +129,7 @@ export function Agent({ className, onRefresh }: AgentProps) {
</div>
);
}

function convertTools(
tools: { tool: string; variant: "fixed" | "default" | "available" }[]
) {
Expand Down
97 changes: 97 additions & 0 deletions ui/admin/app/components/agent/AgentPublishStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Link } from "@remix-run/react";
import { useMemo } from "react";
import { $path } from "remix-routes";
import useSWR from "swr";

import { AgentBase } from "~/lib/model/agents";
import { AssistantApiService } from "~/lib/service/api/assistantApiService";

import { TypographySmall } from "~/components/Typography";
import { Publish } from "~/components/agent/Publish";
import { Unpublish } from "~/components/agent/Unpublish";
import { CopyText } from "~/components/composed/CopyText";

type AgentPublishStatusProps = {
agent: AgentBase;
onChange: (agent: Partial<AgentBase>) => void;
};

export function AgentPublishStatus({
agent,
onChange,
}: AgentPublishStatusProps) {
const getAssistants = useSWR(
() =>
agent.refName && !agent.refNameAssigned
? AssistantApiService.getAssistants.key()
: null,
() => AssistantApiService.getAssistants()
);

const refAgent = useMemo(() => {
if (!getAssistants.data) return null;

return getAssistants.data.find(({ id }) => id === agent.refName);
}, [getAssistants.data, agent.refName]);

return (
<div className="flex w-full justify-between px-8 pt-4 items-center gap-4">
{renderAgentRef()}

{agent.refName ? (
<Unpublish onUnpublish={() => onChange({ refName: "" })} />
) : (
<Publish
refName={agent.refName}
onPublish={(refName) => onChange({ refName })}
/>
)}
</div>
);

function renderAgentRef() {
if (!agent.refName) return <div />;

if (refAgent) {
const route =
refAgent.type === "agent"
? $path("/agents/:agent", {
agent: refAgent.entityID,
})
: $path("/workflows/:workflow", {
workflow: refAgent.entityID,
});

return (
<div className="flex flex-col gap-1 h-full">
<div className="flex items-center gap-2">
<div className="size-2 bg-warning rounded-full" />
<TypographySmall>Unavailable</TypographySmall>
</div>

<TypographySmall className="pb-0 text-muted-foreground">
<span className="min-w-fit">
Ref name <b>{refAgent.id}</b> used by{" "}
</span>
<Link
className="text-accent-foreground underline"
to={route}
>
{refAgent.name}
</Link>
</TypographySmall>
</div>
);
}

if (!agent.refNameAssigned) return <div />;

return (
<CopyText
className="h-8 text-muted-foreground text-sm bg-background flex-row-reverse"
holdStatusDelay={10000}
text={`${window.location.protocol}//${window.location.host}/${agent.refName}`}
/>
);
}
}
21 changes: 9 additions & 12 deletions ui/admin/app/components/agent/Publish.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Eye } from "lucide-react";
import { useState } from "react";

import { Agent } from "~/lib/model/agents";

import {
TypographyMuted,
TypographyMutedAccent,
Expand All @@ -20,19 +18,18 @@ import { Input } from "~/components/ui/input";

type PublishProps = {
className?: string;
agent: Agent;
onChange: (agent: Agent) => void;
refName: string;
onPublish: (refName: string) => void;
};

export function Publish({ className, agent, onChange }: PublishProps) {
const [refName, setRefName] = useState(agent.refName);
export function Publish({
className,
refName: _refName,
onPublish,
}: PublishProps) {
const [refName, setRefName] = useState(_refName);

const handlePublish = () => {
onChange({
...agent,
refName,
});
};
const handlePublish = () => onPublish(refName);

return (
<Dialog>
Expand Down
2 changes: 1 addition & 1 deletion ui/admin/app/components/agent/ToolForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function ToolForm({
onDelete={() => removeTools([field.tool])}
actions={
<Tooltip>
<TooltipTrigger>
<TooltipTrigger asChild>
<Switch
checked={
field.variant ===
Expand Down
18 changes: 4 additions & 14 deletions ui/admin/app/components/agent/Unpublish.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
import { EyeOff } from "lucide-react";

import { Agent } from "~/lib/model/agents";

import { useAgent } from "~/components/agent/AgentContext";
import { ConfirmationDialog } from "~/components/composed/ConfirmationDialog";
import { Button } from "~/components/ui/button";

type PublishProps = {
type UnpublishProps = {
className?: string;
onChange: (agent: Agent) => void;
onUnpublish: () => void;
};

export function Unpublish({ onChange }: PublishProps) {
const { agent } = useAgent();

export function Unpublish({ onUnpublish }: UnpublishProps) {
return (
<ConfirmationDialog
title="Unpublish Agent"
description="Are you sure you want to unpublish this agent? This action will disrupt every user currently using this reference."
onConfirm={() => {
onChange({
...agent,
refName: "",
});
}}
onConfirm={() => onUnpublish()}
confirmProps={{
variant: "destructive",
children: "Unpublish",
Expand Down
10 changes: 8 additions & 2 deletions ui/admin/app/lib/model/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type AgentBase = {
temperature?: number;
cache?: boolean;
refName: string;
refNameAssigned?: boolean;
prompt: string;
agents?: string[];
workflows?: string[];
Expand All @@ -28,10 +29,15 @@ export type AgentOAuthStatus = {

export type Agent = EntityMeta &
AgentBase & {
slugAssigned: boolean;
} & {
authStatus?: Record<string, AgentOAuthStatus>;
};

export type CreateAgent = AgentBase;
export type UpdateAgent = AgentBase;

export type AgentIcons = {
icon: string;
iconDark: string;
collapsed: string;
collapsedDark: string;
};
10 changes: 10 additions & 0 deletions ui/admin/app/lib/model/assistants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { AgentIcons } from "~/lib/model/agents";
import { EntityMeta } from "~/lib/model/primitives";

export type Assistant = EntityMeta & {
name: string;
entityID: string;
description: string;
icons: AgentIcons;
type: "agent" | "workflow";
};
30 changes: 30 additions & 0 deletions ui/admin/app/lib/routers/apiRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,36 @@ const buildUrl = (path: string, params?: object) => {
};

export const ApiRoutes = {
assistants: {
base: () => buildUrl("/assistants"),
getAssistants: () => buildUrl("/assistants"),
getCredentials: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/credentials`),
deleteCredential: (assistantId: string, credentialId: string) =>
buildUrl(`/assistants/${assistantId}/credentials/${credentialId}`),
getEvents: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/events`),
invoke: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/invoke`),
getTools: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/tools`),
deleteTool: (assistantId: string, toolId: string) =>
buildUrl(`/assistants/${assistantId}/tools/${toolId}`),
getFiles: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/files`),
getFileById: (assistantId: string, fileId: string) =>
buildUrl(`/assistants/${assistantId}/files/${fileId}`),
uploadFile: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/files`),
deleteFile: (assistantId: string, fileId: string) =>
buildUrl(`/assistants/${assistantId}/files/${fileId}`),
getKnowledge: (assistantId: string) =>
buildUrl(`/assistants/${assistantId}/knowledge`),
addKnowledge: (assistantId: string, fileName: string) =>
buildUrl(`/assistants/${assistantId}/knowledge/${fileName}`),
deleteKnowledge: (assistantId: string, fileName: string) =>
buildUrl(`/assistants/${assistantId}/knowledge/${fileName}`),
},
agents: {
base: () => buildUrl("/agents"),
getById: (agentId: string) => buildUrl(`/agents/${agentId}`),
Expand Down
16 changes: 16 additions & 0 deletions ui/admin/app/lib/service/api/assistantApiService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Assistant } from "~/lib/model/assistants";
import { ApiRoutes } from "~/lib/routers/apiRoutes";
import { request } from "~/lib/service/api/primitives";

async function getAssistants() {
const { data } = await request<{ items: Assistant[] }>({
url: ApiRoutes.assistants.getAssistants().url,
});

return data.items ?? [];
}
getAssistants.key = () => ({ url: ApiRoutes.assistants.getAssistants().path });

export const AssistantApiService = {
getAssistants,
};
6 changes: 5 additions & 1 deletion ui/admin/app/routes/_auth.agents.$agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ export default function ChatAgent() {
className="flex-auto"
>
<ResizablePanel className="">
<Agent agent={agent} onRefresh={updateThreadId} />
<Agent
agent={agent}
onRefresh={updateThreadId}
key={agent.id}
/>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel>
Expand Down

0 comments on commit 36f9e02

Please sign in to comment.