Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: model provider disable flows if not set & banner updates #949

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 0 additions & 41 deletions ui/admin/app/components/agent/FirstModelProviderBanner.tsx

This file was deleted.

40 changes: 25 additions & 15 deletions ui/admin/app/components/chat/Chatbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { cn } from "~/lib/utils";

import { ChatActions } from "~/components/chat/ChatActions";
import { useChat } from "~/components/chat/ChatContext";
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";
import { useModelProviders } from "~/hooks/model-providers/useModelProviders";

type ChatbarProps = {
className?: string;
Expand All @@ -17,6 +19,7 @@ export function Chatbar({ className }: ChatbarProps) {
const [input, setInput] = useState("");
const { abortRunningThread, processUserMessage, isRunning, isInvoking } =
useChat();
const { configured: modelProviderConfigured } = useModelProviders();

const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
Expand Down Expand Up @@ -54,22 +57,29 @@ export function Chatbar({ className }: ChatbarProps) {
placeholder="Type your message..."
bottomContent={
<div className="flex flex-row-reverse items-center justify-between">
<Button
size="icon-sm"
className="m-2"
color="primary"
type="submit"
disabled={(!input && !isRunning) || isInvoking}
<ModelProviderTooltip
enabled={modelProviderConfigured}
>
{isInvoking ? (
<LoadingSpinner />
) : isRunning ? (
<SquareIcon className="fill-primary-foreground text-primary-foreground !w-3 !h-3" />
) : (
<ArrowUpIcon />
)}
</Button>

<Button
size="icon-sm"
className="m-2"
color="primary"
type="submit"
disabled={
(!input && !isRunning) ||
isInvoking ||
!modelProviderConfigured
}
>
{isInvoking ? (
<LoadingSpinner />
) : isRunning ? (
<SquareIcon className="fill-primary-foreground text-primary-foreground !w-3 !h-3" />
) : (
<ArrowUpIcon />
)}
</Button>
</ModelProviderTooltip>
<ChatActions className="p-2" />
</div>
}
Expand Down
26 changes: 16 additions & 10 deletions ui/admin/app/components/chat/RunWorkflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { WorkflowService } from "~/lib/service/api/workflowService";
import { cn } from "~/lib/utils";

import { RunWorkflowForm } from "~/components/chat/RunWorkflowForm";
import { ModelProviderTooltip } from "~/components/model-providers/ModelProviderTooltip";
import { Button, ButtonProps } from "~/components/ui/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import { useModelProviders } from "~/hooks/model-providers/useModelProviders";

type RunWorkflowProps = {
onSubmit: (params?: Record<string, string>) => void;
Expand All @@ -25,24 +27,28 @@ export function RunWorkflow({
...props
}: RunWorkflowProps & ButtonProps) {
const [open, setOpen] = useState(false);

const { configured: modelProviderConfigured } = useModelProviders();
const { data: workflow, isLoading } = useSWR(
WorkflowService.getWorkflowById.key(workflowId),
({ workflowId }) => WorkflowService.getWorkflowById(workflowId)
);

const params = workflow?.params;

if (!params || isLoading)
if (!params || isLoading || !modelProviderConfigured)
return (
<Button
onClick={() => onSubmit()}
{...props}
disabled={props.disabled || isLoading}
loading={isLoading || props.loading}
>
Run Workflow
</Button>
<ModelProviderTooltip enabled={modelProviderConfigured}>
<Button
onClick={() => onSubmit()}
{...props}
disabled={
props.disabled || isLoading || !modelProviderConfigured
}
loading={isLoading || props.loading}
>
Run Workflow
</Button>
</ModelProviderTooltip>
);

return (
Expand Down
49 changes: 49 additions & 0 deletions ui/admin/app/components/composed/FirstModelProviderBanner.tsx
Original file line number Diff line number Diff line change
@@ -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 { Button } from "~/components/ui/button";
import { useModelProviders } from "~/hooks/model-providers/useModelProviders";

export function FirstModelProviderBanner() {
const { configured: modelProviderConfigured } = useModelProviders();
const location = useLocation();
const isModelsProviderPage = location.pathname.includes("/model-providers");

return isModelsProviderPage || modelProviderConfigured ? null : (
<div className="w-full">
<div className="flex justify-center mx-8 mt-4 py-4 bg-secondary overflow-hidden rounded-xl">
<div className="flex flex-row min-h-36 items-center justify-between w-[calc(100%-4rem)] rounded-sm relative gap-4 max-w-screen-md">
<div className="absolute opacity-5 md:opacity-45 md:top-[-1.75rem] md:left-[-3.0rem]">
<img
alt="Obot Alert"
className="md:h-[17.5rem] md:w-[17.5rem]"
src={assetUrl(
"logo/obot-icon-surprised-yellow.svg"
)}
/>
</div>
<div className="flex flex-col md:ml-64 relative z-10 gap-1">
<TypographyH3 className="mb-0.5">
Wait! You need to set up a Model Provider!
</TypographyH3>
<TypographyP className="text-sm font-light mb-2">
You&apos;re almost there! To start creating or using{" "}
Obot&apos;s features, you&apos;ll need access to an
LLM (Large Language Model) <b>Model Provider</b>.
Luckily, we support a variety of providers to help
get you started.
</TypographyP>
<Button className="mt-0 w-fit px-10" variant="warning">
<Link to={$path("/model-providers")}>
Get Started
</Link>
</Button>
</div>
</div>
</div>
</div>
);
}
26 changes: 26 additions & 0 deletions ui/admin/app/components/model-providers/ModelProviderTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "~/components/ui/tooltip";

export function ModelProviderTooltip({
children,
enabled,
}: {
children: React.ReactNode;
enabled: boolean;
}) {
return enabled ? (
children
) : (
<Tooltip>
<TooltipTrigger asChild>
<span>{children}</span>
</TooltipTrigger>
<TooltipContent className="bg-warning">
Set up a model provider to enable this feature.
</TooltipContent>
</Tooltip>
);
}
2 changes: 2 additions & 0 deletions ui/admin/app/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ 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-primary-foreground shadow-sm hover:bg-warning/80",
},
size: {
none: "",
Expand Down
15 changes: 15 additions & 0 deletions ui/admin/app/hooks/model-providers/useModelProviders.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import useSWR from "swr";

import { ModelProviderApiService } from "~/lib/service/api/modelProviderApiService";

export function useModelProviders() {
const { data: modelProviders } = useSWR(
ModelProviderApiService.getModelProviders.key(),
() => ModelProviderApiService.getModelProviders()
);
const configured =
modelProviders?.some((modelProvider) => modelProvider.configured) ??
false;

return { configured, modelProviders: modelProviders ?? [] };
}
16 changes: 0 additions & 16 deletions ui/admin/app/routes/_auth.agents._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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;
}
Expand All @@ -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(
Expand All @@ -67,21 +56,16 @@ export default function Agents() {
);

const agents = getAgents.data || [];
const modelProviderConfigured = modelProviders?.some(
(modelProvider) => modelProvider.configured
);

return (
<div>
{modelProviderConfigured ? null : <FirstModelProviderBanner />}
<div className="h-full p-8 flex flex-col gap-4">
<div className="flex-auto overflow-hidden">
<div className="flex space-x-2 width-full justify-between mb-8">
<TypographyH2>Agents</TypographyH2>
<Button
variant="outline"
className="justify-start"
disabled={!modelProviderConfigured}
onClick={() => {
AgentService.createAgent({
agent: {
Expand Down
28 changes: 10 additions & 18 deletions ui/admin/app/routes/_auth.model-providers.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import useSWR, { preload } from "swr";
import { preload } from "swr";

import { ModelProvider } from "~/lib/model/modelProviders";
import { DefaultModelAliasApiService } from "~/lib/service/api/defaultModelAliasApiService";
import { ModelApiService } from "~/lib/service/api/modelApiService";
import { ModelProviderApiService } from "~/lib/service/api/modelProviderApiService";
import { RouteHandle } from "~/lib/service/routeHandles";

import { TypographyH2 } from "~/components/Typography";
import { WarningAlert } from "~/components/composed/WarningAlert";
import { ModelProviderList } from "~/components/model-providers/ModelProviderLists";
import { CommonModelProviderIds } from "~/components/model-providers/constants";
import { DefaultModelAliasFormDialog } from "~/components/model/DefaultModelAliasForm";
import { useModelProviders } from "~/hooks/model-providers/useModelProviders";

export async function clientLoader() {
await Promise.all([
preload(ModelApiService.getModels.key(), ModelApiService.getModels),
preload(
ModelProviderApiService.getModelProviders.key(),
ModelProviderApiService.getModelProviders
),
preload(
DefaultModelAliasApiService.getAliases.key(),
DefaultModelAliasApiService.getAliases
Expand Down Expand Up @@ -56,15 +52,9 @@ const sortModelProviders = (modelProviders: ModelProvider[]) => {
};

export default function ModelProviders() {
const getModelProviders = useSWR(
ModelProviderApiService.getModelProviders.key(),
ModelProviderApiService.getModelProviders
);

const configured = getModelProviders.data?.some(
(provider) => provider.configured
);
const modelProviders = sortModelProviders(getModelProviders.data ?? []);
const { configured: modelProviderConfigured, modelProviders } =
useModelProviders();
const sortedModelProviders = sortModelProviders(modelProviders);
return (
<div>
<div className="relative space-y-10 px-8 pb-8">
Expand All @@ -73,9 +63,11 @@ export default function ModelProviders() {
<TypographyH2 className="mb-0 pb-0">
Model Providers
</TypographyH2>
<DefaultModelAliasFormDialog disabled={!configured} />
<DefaultModelAliasFormDialog
disabled={!modelProviderConfigured}
/>
</div>
{configured ? null : (
{modelProviderConfigured ? null : (
<WarningAlert
title="No Model Providers Configured!"
description="To use Obot's features, you'll need to
Expand All @@ -86,7 +78,7 @@ export default function ModelProviders() {
</div>

<div className="h-full flex flex-col gap-8 overflow-hidden">
<ModelProviderList modelProviders={modelProviders ?? []} />
<ModelProviderList modelProviders={sortedModelProviders} />
</div>
</div>
</div>
Expand Down
Loading