From bafbe0782a8130912c4ddb57a1ebc0df89df04cb Mon Sep 17 00:00:00 2001 From: Ivy Date: Wed, 18 Dec 2024 12:01:46 -0500 Subject: [PATCH 1/5] fix: model provider disable flows if not set & banner updates --- .../agent/FirstModelProviderBanner.tsx | 41 ---------------- ui/admin/app/components/chat/Chatbar.tsx | 40 +++++++++------ ui/admin/app/components/chat/RunWorkflow.tsx | 26 ++++++---- .../composed/FirstModelProviderBanner.tsx | 49 +++++++++++++++++++ .../model-providers/ModelProviderContext.tsx | 44 +++++++++++++++++ .../model-providers/ModelProviderTooltip.tsx | 24 +++++++++ ui/admin/app/components/ui/button.tsx | 1 + ui/admin/app/routes/_auth.agents._index.tsx | 16 ------ ui/admin/app/routes/_auth.model-providers.tsx | 26 ++++------ ui/admin/app/routes/_auth.tsx | 29 +++++++---- .../logo/obot-icon-surprised-yellow.svg | 18 +++++++ 11 files changed, 206 insertions(+), 108 deletions(-) delete mode 100644 ui/admin/app/components/agent/FirstModelProviderBanner.tsx create mode 100644 ui/admin/app/components/composed/FirstModelProviderBanner.tsx create mode 100644 ui/admin/app/components/model-providers/ModelProviderContext.tsx create mode 100644 ui/admin/app/components/model-providers/ModelProviderTooltip.tsx create mode 100644 ui/admin/public/logo/obot-icon-surprised-yellow.svg diff --git a/ui/admin/app/components/agent/FirstModelProviderBanner.tsx b/ui/admin/app/components/agent/FirstModelProviderBanner.tsx deleted file mode 100644 index 26cdae823..000000000 --- a/ui/admin/app/components/agent/FirstModelProviderBanner.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Link } from "@remix-run/react"; -import { $path } from "remix-routes"; - -import { TypographyH3, TypographyP } from "~/components/Typography"; -import { ObotLogo } from "~/components/branding/ObotLogo"; -import { Button } from "~/components/ui/button"; - -export function FirstModelProviderBanner() { - return ( -
-
-
- -
- - Ready to create your first Agent? - - - You're almost there! To start creating or using{" "} - agents, you'll need access to an LLM (Large - Language Model) Model Provider. Luckily, we - support a variety of providers to help get you - started. - - -
-
-
-
- ); -} diff --git a/ui/admin/app/components/chat/Chatbar.tsx b/ui/admin/app/components/chat/Chatbar.tsx index f1c890282..d04699d06 100644 --- a/ui/admin/app/components/chat/Chatbar.tsx +++ b/ui/admin/app/components/chat/Chatbar.tsx @@ -5,6 +5,8 @@ import { cn } from "~/lib/utils"; import { ChatActions } from "~/components/chat/ChatActions"; import { useChat } from "~/components/chat/ChatContext"; +import { useModelProviders } from "~/components/model-providers/ModelProviderContext"; +import { ModelProviderTooltip } from "~/components/model-providers/ModelProviderTooltip"; import { LoadingSpinner } from "~/components/ui/LoadingSpinner"; import { Button } from "~/components/ui/button"; import { AutosizeTextarea } from "~/components/ui/textarea"; @@ -17,6 +19,7 @@ export function Chatbar({ className }: ChatbarProps) { const [input, setInput] = useState(""); const { abortRunningThread, processUserMessage, isRunning, isInvoking } = useChat(); + const { modelProviderConfigured } = useModelProviders(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -54,22 +57,29 @@ export function Chatbar({ className }: ChatbarProps) { placeholder="Type your message..." bottomContent={
- - + +
} diff --git a/ui/admin/app/components/chat/RunWorkflow.tsx b/ui/admin/app/components/chat/RunWorkflow.tsx index 4c9f2961c..cd2e8bb8b 100644 --- a/ui/admin/app/components/chat/RunWorkflow.tsx +++ b/ui/admin/app/components/chat/RunWorkflow.tsx @@ -5,6 +5,8 @@ import { WorkflowService } from "~/lib/service/api/workflowService"; import { cn } from "~/lib/utils"; import { RunWorkflowForm } from "~/components/chat/RunWorkflowForm"; +import { useModelProviders } from "~/components/model-providers/ModelProviderContext"; +import { ModelProviderTooltip } from "~/components/model-providers/ModelProviderTooltip"; import { Button, ButtonProps } from "~/components/ui/button"; import { Popover, @@ -25,7 +27,7 @@ export function RunWorkflow({ ...props }: RunWorkflowProps & ButtonProps) { const [open, setOpen] = useState(false); - + const { modelProviderConfigured } = useModelProviders(); const { data: workflow, isLoading } = useSWR( WorkflowService.getWorkflowById.key(workflowId), ({ workflowId }) => WorkflowService.getWorkflowById(workflowId) @@ -33,16 +35,20 @@ export function RunWorkflow({ const params = workflow?.params; - if (!params || isLoading) + if (!params || isLoading || !modelProviderConfigured) return ( - + + + ); return ( diff --git a/ui/admin/app/components/composed/FirstModelProviderBanner.tsx b/ui/admin/app/components/composed/FirstModelProviderBanner.tsx new file mode 100644 index 000000000..9a21100a3 --- /dev/null +++ b/ui/admin/app/components/composed/FirstModelProviderBanner.tsx @@ -0,0 +1,49 @@ +import { Link, useLocation } from "@remix-run/react"; +import { $path } from "remix-routes"; + +import { assetUrl } from "~/lib/utils"; + +import { TypographyH3, TypographyP } from "~/components/Typography"; +import { useModelProviders } from "~/components/model-providers/ModelProviderContext"; +import { Button } from "~/components/ui/button"; + +export function FirstModelProviderBanner() { + const { modelProviderConfigured } = useModelProviders(); + const location = useLocation(); + const isModelsProviderPage = location.pathname.includes("/model-providers"); + + return isModelsProviderPage || modelProviderConfigured ? null : ( +
+
+
+
+ Obot Alert +
+
+ + Wait! You need to set up a Model Provider! + + + You're almost there! To start creating or using{" "} + Obot's features, you'll need access to an + LLM (Large Language Model) Model Provider. + Luckily, we support a variety of providers to help + get you started. + + +
+
+
+
+ ); +} diff --git a/ui/admin/app/components/model-providers/ModelProviderContext.tsx b/ui/admin/app/components/model-providers/ModelProviderContext.tsx new file mode 100644 index 000000000..254f855e0 --- /dev/null +++ b/ui/admin/app/components/model-providers/ModelProviderContext.tsx @@ -0,0 +1,44 @@ +import { ReactNode, createContext, useContext } from "react"; +import useSWR from "swr"; + +import { ModelProvider } from "~/lib/model/modelProviders"; +import { ModelProviderApiService } from "~/lib/service/api/modelProviderApiService"; + +interface ModelProviderContextType { + modelProviderConfigured: boolean; + modelProviders: ModelProvider[]; +} + +const ModelProviderContext = createContext< + ModelProviderContextType | undefined +>(undefined); + +export function ModelProviderProvider({ children }: { children: ReactNode }) { + const { data: modelProviders } = useSWR( + ModelProviderApiService.getModelProviders.key(), + () => ModelProviderApiService.getModelProviders() + ); + const modelProviderConfigured = + modelProviders?.some((modelProvider) => modelProvider.configured) ?? + false; + return ( + + {children} + + ); +} + +export function useModelProviders() { + const context = useContext(ModelProviderContext); + if (context === undefined) { + throw new Error( + "useModelProvider must be used within a ModelProviderProvider" + ); + } + return context; +} diff --git a/ui/admin/app/components/model-providers/ModelProviderTooltip.tsx b/ui/admin/app/components/model-providers/ModelProviderTooltip.tsx new file mode 100644 index 000000000..3d2884558 --- /dev/null +++ b/ui/admin/app/components/model-providers/ModelProviderTooltip.tsx @@ -0,0 +1,24 @@ +import { + Tooltip, + TooltipContent, + TooltipTrigger, +} from "~/components/ui/tooltip"; + +export function ModelProviderTooltip({ + children, + enabled, +}: { + children: React.ReactNode; + enabled: boolean; +}) { + return enabled ? ( + children + ) : ( + + {children} + + Set up a model provider to enable this feature. + + + ); +} diff --git a/ui/admin/app/components/ui/button.tsx b/ui/admin/app/components/ui/button.tsx index 6cc017ced..9a31d99ad 100644 --- a/ui/admin/app/components/ui/button.tsx +++ b/ui/admin/app/components/ui/button.tsx @@ -21,6 +21,7 @@ const buttonVariants = cva( ghost: "hover:bg-secondary hover:text-secondary-foreground", accent: "bg-accent text-accent-foreground shadow-sm hover:bg-accent/80", link: "text-primary hover:text-primary/70 underline-offset-4 hover:underline shadow-none hover:shadow-none", + warning: "bg-warning text-black shadow-sm hover:bg-warning/80", }, size: { none: "", diff --git a/ui/admin/app/routes/_auth.agents._index.tsx b/ui/admin/app/routes/_auth.agents._index.tsx index cebc80054..477362522 100644 --- a/ui/admin/app/routes/_auth.agents._index.tsx +++ b/ui/admin/app/routes/_auth.agents._index.tsx @@ -8,14 +8,12 @@ import useSWR, { mutate, preload } from "swr"; import { Agent } from "~/lib/model/agents"; import { AgentService } from "~/lib/service/api/agentService"; -import { ModelProviderApiService } from "~/lib/service/api/modelProviderApiService"; import { ThreadsService } from "~/lib/service/api/threadsService"; import { generateRandomName } from "~/lib/service/nameGenerator"; import { timeSince } from "~/lib/utils"; import { TypographyH2, TypographyP } from "~/components/Typography"; import { DeleteAgent } from "~/components/agent/DeleteAgent"; -import { FirstModelProviderBanner } from "~/components/agent/FirstModelProviderBanner"; import { DataTable } from "~/components/composed/DataTable"; import { Button } from "~/components/ui/button"; import { Link } from "~/components/ui/link"; @@ -30,10 +28,6 @@ export async function clientLoader() { await Promise.all([ preload(AgentService.getAgents.key(), AgentService.getAgents), preload(ThreadsService.getThreads.key(), ThreadsService.getThreads), - preload( - ModelProviderApiService.getModelProviders.key(), - ModelProviderApiService.getModelProviders - ), ]); return null; } @@ -44,11 +38,6 @@ export default function Agents() { ThreadsService.getThreads() ); - const { data: modelProviders } = useSWR( - ModelProviderApiService.getModelProviders.key(), - () => ModelProviderApiService.getModelProviders() - ); - const threadCounts = useMemo(() => { if (!getThreads.data) return {}; return getThreads.data.reduce( @@ -67,13 +56,9 @@ export default function Agents() { ); const agents = getAgents.data || []; - const modelProviderConfigured = modelProviders?.some( - (modelProvider) => modelProvider.configured - ); return (
- {modelProviderConfigured ? null : }
@@ -81,7 +66,6 @@ export default function Agents() {