Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const AssistantUiChat = ({

const {
selectedModel,
selectedProvider,
availableModels,
onModelSelected,
isLoading: isModelSelectorLoading,
Expand Down Expand Up @@ -146,6 +147,7 @@ const AssistantUiChat = ({
onModelSelected={onModelSelected}
isModelSelectorLoading={isModelSelectorLoading}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
theme={theme}
handleInject={handleInject}
toolComponents={toolComponents}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export const useAiModelSelector = ({

return {
selectedModel,
availableModels: providerModels?.models ?? [],
selectedProvider: provider,
availableModels:
providerModels?.models.map((m) => ({ name: m, provider })) ?? [],
isLoading: isLoadingProviderModels || isSaving,
onModelSelected,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const StepSettingsAssistantUiChat = ({

const {
selectedModel,
selectedProvider,
availableModels,
onModelSelected,
isLoading: isModelSelectorLoading,
Expand Down Expand Up @@ -106,6 +107,7 @@ const StepSettingsAssistantUiChat = ({
onModelSelected={onModelSelected}
isModelSelectorLoading={isModelSelectorLoading}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
availableModels={availableModels}
theme={theme}
runtime={runtime}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ import {
import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
import { ScrollArea } from '../../ui/scroll-area';
import { LoadingSpinner } from '../../ui/spinner';
import { AiProviderIcon } from './ai-provider-icon';

type AiModelInfo = {
name: string;
provider?: string;
};

type AiModelSelectorProps = {
selectedModel?: string;
availableModels: string[];
selectedProvider?: string;
availableModels: AiModelInfo[];
onModelSelected: (modelName: string) => void;
isModelSelectorLoading: boolean;
className?: string;
};

const AiModelSelector = ({
selectedModel,
selectedProvider,
availableModels,
onModelSelected,
isModelSelectorLoading,
Expand Down Expand Up @@ -66,6 +74,10 @@ const AiModelSelector = ({
variant="secondary"
className="flex items-center gap-1 rounded-xs"
>
<AiProviderIcon
provider={selectedProvider}
className="text-muted-foreground"
/>
{selectedModel}
{isModelSelectorLoading && <LoadingSpinner size={12} />}
{hasOptions && !isModelSelectorLoading && (
Expand All @@ -87,20 +99,26 @@ const AiModelSelector = ({
>
{availableModels.map((model) => (
<CommandItem
key={model}
value={model}
onSelect={() => handleSelect(model)}
key={model.name}
value={model.name}
onSelect={() => handleSelect(model.name)}
>
<div className="flex items-center gap-2 flex-1">
<AiProviderIcon
provider={model.provider}
className="text-muted-foreground"
/>
<span>{model.name}</span>
</div>
<Check
size={16}
className={cn(
'mr-2',
selectedModel === model
selectedModel === model.name
? 'opacity-100'
: 'opacity-0',
)}
/>
Comment on lines +106 to 121
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Check icon appears after the model name/provider icon, but the layout order suggests it should appear at the end. Consider moving the Check icon inside the flex container or adjusting the flex layout to ensure proper alignment of all elements (icon, name, and check mark).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the point, but it's fine imo

image

{model}
</CommandItem>
))}
</ScrollArea>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { AiProviderEnum } from '@openops/shared';
import { Bot } from 'lucide-react';
import AnthropicIcon from '../../icons/anthropic.icon';
import CerebrasIcon from '../../icons/cerebras.icon';
import CohereIcon from '../../icons/cohere.icon';
import DeepInfraIcon from '../../icons/deepinfra.icon';
import DeepSeekIcon from '../../icons/deepseek.icon';
import GeminiIcon from '../../icons/gemini.icon';
import GoogleIcon from '../../icons/google.icon';
import GrokIcon from '../../icons/grok.icon';
import MistralIcon from '../../icons/mistral.icon';
import OpenAiIcon from '../../icons/open-ai.icon';
import PerplexityIcon from '../../icons/perplexity.icon';
import TogetherAiIcon from '../../icons/together-ai.icon';
import { cn } from '../../lib/cn';

interface AiProviderIconProps {
provider?: string;
className?: string;
size?: number;
}

const AiProviderIcon = ({
provider,
className,
size = 16,
}: AiProviderIconProps) => {
const iconProps = {
size,
className: cn('shrink-0', className),
};

switch (provider) {
case AiProviderEnum.OPENAI:
case AiProviderEnum.AZURE_OPENAI:
return <OpenAiIcon {...iconProps} />;
case AiProviderEnum.ANTHROPIC:
return <AnthropicIcon {...iconProps} />;
case AiProviderEnum.GOOGLE:
return <GeminiIcon {...iconProps} />;
case AiProviderEnum.GOOGLE_VERTEX:
return <GoogleIcon {...iconProps} />;
case AiProviderEnum.MISTRAL:
return <MistralIcon {...iconProps} />;
case AiProviderEnum.GROQ:
case AiProviderEnum.XAI:
return <GrokIcon {...iconProps} />;
case AiProviderEnum.DEEPSEEK:
return <DeepSeekIcon {...iconProps} />;
case AiProviderEnum.PERPLEXITY:
return <PerplexityIcon {...iconProps} />;
case AiProviderEnum.COHERE:
return <CohereIcon {...iconProps} />;
case AiProviderEnum.CEREBRAS:
return <CerebrasIcon {...iconProps} />;
case AiProviderEnum.DEEPINFRA:
return <DeepInfraIcon {...iconProps} />;
case AiProviderEnum.TOGETHER_AI:
return <TogetherAiIcon {...iconProps} />;
default:
return <Bot {...iconProps} />;
}
};

export { AiProviderIcon };
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const AssistantUiChatContainer = ({
title,
availableModels,
selectedModel,
selectedProvider,
onModelSelected,
isModelSelectorLoading,
theme,
Expand Down Expand Up @@ -86,6 +87,7 @@ const AssistantUiChatContainer = ({
availableModels={availableModels}
onModelSelected={onModelSelected}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
isModelSelectorLoading={isModelSelectorLoading}
theme={theme}
isShowingSlowWarning={isShowingSlowWarning}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ExpandIcon, MinimizeIcon } from 'lucide-react';
import { useRef } from 'react';
import { cn } from '../../lib/cn';
import { Button } from '../../ui/button';
import { AiModelSelectorProps } from '../ai-chat-container/ai-model-selector';
import {
AI_CHAT_CONTAINER_SIZES,
AiCliChatContainerSizeState,
Expand All @@ -32,7 +33,8 @@ type StepSettingsAssistantUiChatContainerProps = {
className?: string;
isModelSelectorLoading: boolean;
selectedModel?: string;
availableModels: string[];
selectedProvider?: string;
availableModels: AiModelSelectorProps['availableModels'];
onModelSelected: (modelName: string) => void;
runtime: AssistantRuntime;
theme: Theme;
Expand All @@ -55,6 +57,7 @@ const StepSettingsAssistantUiChatContainer = ({
className,
isModelSelectorLoading,
selectedModel,
selectedProvider,
availableModels,
onModelSelected,
runtime,
Expand Down Expand Up @@ -106,6 +109,7 @@ const StepSettingsAssistantUiChatContainer = ({
<AssistantUiChatContainer
handleInject={handleInject}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
onModelSelected={onModelSelected}
isModelSelectorLoading={isModelSelectorLoading}
runtime={runtime}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const Thread = ({
theme,
availableModels,
selectedModel,
selectedProvider,
onModelSelected,
isModelSelectorLoading,
isShowingSlowWarning,
Expand Down Expand Up @@ -101,6 +102,7 @@ export const Thread = ({
<Composer
availableModels={availableModels}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
onModelSelected={onModelSelected}
isModelSelectorLoading={isModelSelectorLoading}
connectionError={connectionError}
Expand Down Expand Up @@ -146,6 +148,7 @@ type ComposerProps = AiModelSelectorProps & {
const Composer = ({
availableModels,
selectedModel,
selectedProvider,
onModelSelected,
isModelSelectorLoading,
connectionError,
Expand All @@ -166,6 +169,7 @@ const Composer = ({
<AiModelSelector
availableModels={availableModels}
selectedModel={selectedModel}
selectedProvider={selectedProvider}
onModelSelected={onModelSelected}
isModelSelectorLoading={isModelSelectorLoading}
className="absolute left-3 bottom-3"
Expand Down
28 changes: 28 additions & 0 deletions packages/ui-components/src/icons/anthropic.icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { LucideProps } from 'lucide-react';

const AnthropicIcon = ({
size = 16,
color = 'currentColor',
...props
}: LucideProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 16 16"
fill="none"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.218 2.34668H11.62L16 13.3333H13.598L9.218 2.34668ZM4.37933 2.34668H6.89067L11.2707 13.3333H8.82133L7.926 11.026H3.34467L2.44867 13.3327H0L4.38 2.34801L4.37933 2.34668ZM7.134 8.98601L5.63533 5.12468L4.13667 8.98668H7.13333L7.134 8.98601Z"
fill={color}
/>
</svg>
);
};

AnthropicIcon.displayName = 'AnthropicIcon';
export default AnthropicIcon;
30 changes: 30 additions & 0 deletions packages/ui-components/src/icons/cerebras.icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { LucideProps } from 'lucide-react';

const CerebrasIcon = ({
size = 16,
color = 'currentColor',
...props
}: LucideProps) => {
return (
<svg
fill={color}
height={size}
width={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
{...props}
>
<title>Cerebras</title>
<path
clipRule="evenodd"
d="M14.121 2.701a9.299 9.299 0 000 18.598V22.7c-5.91 0-10.7-4.791-10.7-10.701S8.21 1.299 14.12 1.299V2.7zm4.752 3.677A7.353 7.353 0 109.42 17.643l-.901 1.074a8.754 8.754 0 01-1.08-12.334 8.755 8.755 0 0112.335-1.08l-.901 1.075zm-2.255.844a5.407 5.407 0 00-5.048 9.563l-.656 1.24a6.81 6.81 0 016.358-12.043l-.654 1.24zM14.12 8.539a3.46 3.46 0 100 6.922v1.402a4.863 4.863 0 010-9.726v1.402z"
></path>
<path d="M15.407 10.836a2.24 2.24 0 00-.51-.409 1.084 1.084 0 00-.544-.152c-.255 0-.483.047-.684.14a1.58 1.58 0 00-.84.912c-.074.203-.11.416-.11.631 0 .218.036.43.11.631a1.594 1.594 0 00.84.913c.2.093.43.14.684.14.216 0 .417-.046.602-.135.188-.09.35-.225.475-.392l.928 1.006c-.14.14-.3.261-.482.363a3.367 3.367 0 01-1.083.38c-.17.026-.317.04-.44.04a3.315 3.315 0 01-1.182-.21 2.825 2.825 0 01-.961-.597 2.816 2.816 0 01-.644-.929 2.987 2.987 0 01-.238-1.21c0-.444.08-.847.238-1.21.15-.35.368-.666.643-.929.278-.261.605-.464.962-.596a3.315 3.315 0 011.182-.21c.355 0 .712.068 1.072.204.361.138.685.36.944.649l-.962.97z"></path>
</svg>
);
};

CerebrasIcon.displayName = 'CerebrasIcon';
export default CerebrasIcon;
34 changes: 34 additions & 0 deletions packages/ui-components/src/icons/cohere.icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { LucideProps } from 'lucide-react';

const CohereIcon = ({
size = 16,
color = 'currentColor',
...props
}: LucideProps) => {
return (
<svg
fill={color}
height={size}
width={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
{...props}
>
<title>Cohere</title>
<path
clipRule="evenodd"
d="M8.128 14.099c.592 0 1.77-.033 3.398-.703 1.897-.781 5.672-2.2 8.395-3.656 1.905-1.018 2.74-2.366 2.74-4.18A4.56 4.56 0 0018.1 1H7.549A6.55 6.55 0 001 7.55c0 3.617 2.745 6.549 7.128 6.549z"
></path>
<path
clipRule="evenodd"
d="M9.912 18.61a4.387 4.387 0 012.705-4.052l3.323-1.38c3.361-1.394 7.06 1.076 7.06 4.715a5.104 5.104 0 01-5.105 5.104l-3.597-.001a4.386 4.386 0 01-4.386-4.387z"
></path>
<path d="M4.776 14.962A3.775 3.775 0 001 18.738v.489a3.776 3.776 0 007.551 0v-.49a3.775 3.775 0 00-3.775-3.775z"></path>
</svg>
);
};

CohereIcon.displayName = 'CohereIcon';
export default CohereIcon;
27 changes: 27 additions & 0 deletions packages/ui-components/src/icons/deepinfra.icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { LucideProps } from 'lucide-react';

const DeepInfraIcon = ({
size = 16,
color = 'currentColor',
strokeWidth = 1,
...props
}: LucideProps) => {
return (
<svg
fill={color}
fillRule="evenodd"
height={size}
viewBox="0 0 24 24"
width={size}
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<title>DeepInfra</title>
<path d="M3.294 7.821A2.297 2.297 0 011 5.527a2.297 2.297 0 012.294-2.295A2.297 2.297 0 015.59 5.527 2.297 2.297 0 013.294 7.82zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM3.294 14.293A2.297 2.297 0 011 11.998a2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.295 2.295zm0-3.688a1.395 1.395 0 000 2.788 1.395 1.395 0 100-2.788zM3.294 20.761A2.297 2.297 0 011 18.467a2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 000 2.79 1.396 1.396 0 000-2.79zM20.738 7.821a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM20.738 14.293a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688c-.769 0-1.395.625-1.395 1.393a1.396 1.396 0 002.79 0c0-.77-.626-1.393-1.395-1.393zM20.738 20.761a2.297 2.297 0 01-2.295-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.294 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 11.057a2.297 2.297 0 01-2.294-2.294 2.297 2.297 0 012.294-2.295 2.297 2.297 0 012.295 2.295 2.297 2.297 0 01-2.295 2.294zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395zM12.017 4.589a2.297 2.297 0 01-2.295-2.295A2.297 2.297 0 0112.017 0a2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.017 17.529a2.297 2.297 0 01-2.295-2.295 2.297 2.297 0 012.295-2.294 2.297 2.297 0 012.294 2.294 2.297 2.297 0 01-2.294 2.295zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.626-1.395-1.395-1.395zM12.016 24a2.297 2.297 0 01-2.294-2.295 2.297 2.297 0 012.294-2.294 2.297 2.297 0 012.295 2.294A2.297 2.297 0 0112.016 24zm0-3.688a1.396 1.396 0 101.395 1.395c0-.77-.625-1.395-1.395-1.395z"></path>
<path d="M8.363 8.222a.742.742 0 01-.277-.053l-1.494-.596a.75.75 0 11.557-1.392l1.493.595a.75.75 0 01-.278 1.446h-.001zM8.363 14.566a.743.743 0 01-.277-.053l-1.494-.595a.75.75 0 11.557-1.393l1.493.596a.75.75 0 01-.278 1.445h-.001zM17.124 11.397a.741.741 0 01-.277-.054l-1.493-.595a.75.75 0 11.555-1.392l1.493.595a.75.75 0 01-.278 1.446zM17.124 5.05a.744.744 0 01-.277-.054L15.354 4.4a.75.75 0 01.555-1.392l1.493.596a.75.75 0 01-.278 1.445zM17.124 17.739a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 11.556-1.392l1.493.596a.75.75 0 01-.278 1.445zM6.91 17.966a.75.75 0 01-.279-1.445l1.494-.595a.749.749 0 11.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 11.66a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.595a.743.743 0 01-.277.053H6.91zM6.91 5.033a.75.75 0 01-.279-1.446l1.494-.595a.75.75 0 01.556 1.392l-1.493.596a.744.744 0 01-.277.053H6.91zM8.363 21.364a.743.743 0 01-.277-.053l-1.494-.596a.75.75 0 01.555-1.392l1.494.595a.75.75 0 01-.278 1.446zM15.63 8.223a.75.75 0 01-.278-1.447l1.494-.595a.75.75 0 01.556 1.393l-1.494.595a.744.744 0 01-.276.054h-.002zM15.63 14.567a.75.75 0 01-.278-1.446l1.494-.596a.75.75 0 01.556 1.394l-1.494.595a.743.743 0 01-.276.053h-.002zM15.63 21.363a.749.749 0 01-.278-1.445l1.494-.595a.75.75 0 11.555 1.392l-1.494.595a.741.741 0 01-.277.053z"></path>
</svg>
);
};

DeepInfraIcon.displayName = 'DeepInfraIcon';
export default DeepInfraIcon;
Loading
Loading