feat(provider): add agent support filter for provider list

- Add filter dropdown in provider search to filter by agent support
- Create AnthropicProviderListPopover component for showing supported providers
- Add filter=agent URL parameter support in ProviderList
- Update AgentModal and CodeToolsPage to use the new popover component
- Add getAnthropicSupportedProviders utility function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kangfenmao 2025-12-15 23:54:10 +08:00
parent d41229c69b
commit ddfbce071b
16 changed files with 338 additions and 69 deletions

View File

@ -0,0 +1,148 @@
import { ProviderAvatar } from '@renderer/components/ProviderAvatar'
import { useAllProviders } from '@renderer/hooks/useProvider'
import ImageStorage from '@renderer/services/ImageStorage'
import type { Provider } from '@renderer/types'
import { getFancyProviderName } from '@renderer/utils'
import { getClaudeSupportedProviders } from '@renderer/utils/provider'
import type { PopoverProps } from 'antd'
import { Popover } from 'antd'
import { ArrowUpRight, HelpCircle } from 'lucide-react'
import type { FC, ReactNode } from 'react'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
interface AnthropicProviderListPopoverProps {
/** Callback when provider is clicked */
onProviderClick?: () => void
/** Use window.navigate instead of Link (for non-router context like TopView) */
useWindowNavigate?: boolean
/** Custom trigger element, defaults to HelpCircle icon */
children?: ReactNode
/** Popover placement */
placement?: PopoverProps['placement']
/** Custom filter function for providers, defaults to getClaudeSupportedProviders */
filterProviders?: (providers: Provider[]) => Provider[]
}
const AnthropicProviderListPopover: FC<AnthropicProviderListPopoverProps> = ({
onProviderClick,
useWindowNavigate = false,
children,
placement = 'right',
filterProviders = getClaudeSupportedProviders
}) => {
const { t } = useTranslation()
const allProviders = useAllProviders()
const providers = filterProviders(allProviders)
const [providerLogos, setProviderLogos] = useState<Record<string, string>>({})
useEffect(() => {
const loadAllLogos = async () => {
const logos: Record<string, string> = {}
for (const provider of providers) {
if (provider.id) {
try {
const logoData = await ImageStorage.get(`provider-${provider.id}`)
if (logoData) {
logos[provider.id] = logoData
}
} catch {
// Ignore errors loading logos
}
}
}
setProviderLogos(logos)
}
loadAllLogos()
}, [providers])
const handleClick = (providerId: string) => {
onProviderClick?.()
if (useWindowNavigate) {
window.navigate(`/settings/provider?id=${providerId}`)
}
}
const content = (
<PopoverContent>
<PopoverTitle>{t('code.supported_providers')}</PopoverTitle>
<ProviderListContainer>
{providers.map((provider) =>
useWindowNavigate ? (
<ProviderItem key={provider.id} onClick={() => handleClick(provider.id)}>
<ProviderAvatar
provider={provider}
customLogos={providerLogos}
size={20}
style={{ width: 20, height: 20 }}
/>
{getFancyProviderName(provider)}
<ArrowUpRight size={14} />
</ProviderItem>
) : (
<ProviderLink
key={provider.id}
href={`/settings/provider?id=${provider.id}`}
onClick={() => handleClick(provider.id)}>
<ProviderAvatar
provider={provider}
customLogos={providerLogos}
size={20}
style={{ width: 20, height: 20 }}
/>
{getFancyProviderName(provider)}
<ArrowUpRight size={14} />
</ProviderLink>
)
)}
</ProviderListContainer>
</PopoverContent>
)
return (
<Popover content={content} trigger="hover" placement={placement}>
{children || <HelpCircle size={14} style={{ color: 'var(--color-text-3)', cursor: 'pointer' }} />}
</Popover>
)
}
const PopoverContent = styled.div`
width: 200px;
`
const PopoverTitle = styled.div`
margin-bottom: 8px;
font-weight: 500;
`
const ProviderListContainer = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
`
const ProviderItem = styled.div`
color: var(--color-text);
display: flex;
align-items: center;
gap: 4px;
cursor: pointer;
&:hover {
color: var(--color-link);
}
`
const ProviderLink = styled.a`
color: var(--color-text);
display: flex;
align-items: center;
gap: 4px;
text-decoration: none;
&:hover {
color: var(--color-link);
}
`
export default AnthropicProviderListPopover

View File

@ -1,6 +1,6 @@
import { loggerService } from '@logger'
import AnthropicProviderListPopover from '@renderer/components/AnthropicProviderListPopover'
import { ErrorBoundary } from '@renderer/components/ErrorBoundary'
import { HelpTooltip } from '@renderer/components/TooltipIcons'
import { TopView } from '@renderer/components/TopView'
import { permissionModeCards } from '@renderer/config/agent'
import { useAgents } from '@renderer/hooks/agents/useAgents'
@ -16,6 +16,7 @@ import type {
UpdateAgentForm
} from '@renderer/types'
import { AgentConfigurationSchema, isAgentType } from '@renderer/types'
import { getAnthropicSupportedProviders } from '@renderer/utils/provider'
import { Alert, Button, Input, Modal, Select } from 'antd'
import { AlertTriangleIcon } from 'lucide-react'
import type { ChangeEvent, FormEvent } from 'react'
@ -420,7 +421,14 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
<Label>
{t('common.model')} <RequiredMark>*</RequiredMark>
</Label>
<HelpTooltip title={t('agent.add.model.tooltip')} />
<AnthropicProviderListPopover
useWindowNavigate
filterProviders={getAnthropicSupportedProviders}
onProviderClick={() => {
setOpen(false)
resolve(undefined)
}}
/>
</div>
<SelectAgentBaseModelButton
agentBase={tempAgentBase}

View File

@ -7,7 +7,9 @@
"invalid_agent": "Invalid Agent"
},
"model": {
"tooltip": "Currently, only models that support Anthropic endpoints are available for the Agent feature."
"supported_providers": "Supported Providers",
"tooltip": "Currently, only models that support Anthropic endpoints are available for the Agent feature.",
"view_providers": "View supported providers"
},
"title": "Add Agent",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Check",
"docs_more_details": "for more details",
"filter": {
"agent": "Agent Supported",
"all": "All Providers"
},
"filter_agent": "Filter Agent Supported Providers",
"get_api_key": "Get API Key",
"misc": "Other",
"no_models_for_check": "No models available for checking (e.g. chat models)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "无效的 Agent"
},
"model": {
"tooltip": "目前,只有支持 Anthropic 端点的模型可用于 Agent 功能。"
"supported_providers": "支持的服务商",
"tooltip": "目前,只有支持 Anthropic 端点的模型可用于 Agent 功能。",
"view_providers": "查看支持的服务商"
},
"title": "添加 Agent",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "查看",
"docs_more_details": "获取更多详情",
"filter": {
"agent": "支持 Agent",
"all": "全部服务商"
},
"filter_agent": "筛选支持 Agent 的服务商",
"get_api_key": "点击这里获取密钥",
"misc": "其他",
"no_models_for_check": "没有可以被检测的模型(例如对话模型)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "無效的 Agent"
},
"model": {
"tooltip": "目前,僅支援 Anthropic 端點的模型可供代理功能使用。"
"supported_providers": "支援的服務商",
"tooltip": "目前,僅支援 Anthropic 端點的模型可供代理功能使用。",
"view_providers": "檢視支援的服務商"
},
"title": "新增 Agent",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "檢查",
"docs_more_details": "檢視更多細節",
"filter": {
"agent": "支援 Agent",
"all": "全部服務商"
},
"filter_agent": "篩選支援 Agent 的服務商",
"get_api_key": "點選這裡取得金鑰",
"misc": "其他",
"no_models_for_check": "沒有可以被檢查的模型(例如對話模型)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Ungültiger Agent"
},
"model": {
"tooltip": "Derzeit sind für die Agent-Funktion nur Modelle verfügbar, die Anthropic-Endpunkte unterstützen."
"supported_providers": "Unterstützte Anbieter",
"tooltip": "Derzeit sind für die Agent-Funktion nur Modelle verfügbar, die Anthropic-Endpunkte unterstützen.",
"view_providers": "Unterstützte Anbieter anzeigen"
},
"title": "Agent hinzufügen",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Anzeigen",
"docs_more_details": "Weitere Details anzeigen",
"filter": {
"agent": "Vom Agenten unterstützt",
"all": "Alle Anbieter"
},
"filter_agent": "Von Filter-Agent unterstützte Anbieter",
"get_api_key": "Hier klicken um Schlüssel zu erhalten",
"misc": "Sonstige",
"no_models_for_check": "Keine testbaren Modelle (z.B. Chat-Modelle)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Μη έγκυρος Agent"
},
"model": {
"tooltip": "Προς το παρόν, μόνο μοντέλα που υποστηρίζουν τελικά σημεία Anthropic είναι διαθέσιμα για τη λειτουργία Agent."
"supported_providers": "Υποστηριζόμενοι Πάροχοι",
"tooltip": "Προς το παρόν, μόνο μοντέλα που υποστηρίζουν τελικά σημεία Anthropic είναι διαθέσιμα για τη λειτουργία Agent.",
"view_providers": "Δείτε τους υποστηριζόμενους παρόχους"
},
"title": "Προσθήκη Agent",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Άνοιγμα",
"docs_more_details": "Λάβετε περισσότερες λεπτομέρειες",
"filter": {
"agent": "Υποστηριζόμενος από πράκτορα",
"all": "Όλοι οι Πάροχοι"
},
"filter_agent": "Υποστηριζόμενοι Πάροχοι του Φίλτρου Πράκτορα",
"get_api_key": "Κάντε κλικ εδώ για να πάρετε κλειδί",
"misc": "Άλλο",
"no_models_for_check": "Δεν υπάρχουν μοντέλα για έλεγχο (π.χ. μοντέλα συνομιλίας)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Agent inválido"
},
"model": {
"tooltip": "Actualmente, solo los modelos que admiten puntos finales de Anthropic están disponibles para la función Agente."
"supported_providers": "Proveedores Admitidos",
"tooltip": "Actualmente, solo los modelos que admiten puntos finales de Anthropic están disponibles para la función Agente.",
"view_providers": "Ver proveedores compatibles"
},
"title": "Agregar Agente",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Ver",
"docs_more_details": "Obtener más detalles",
"filter": {
"agent": "Soporte de Agente",
"all": "Todos los Proveedores"
},
"filter_agent": "Proveedores compatibles con el agente de filtrado",
"get_api_key": "Haga clic aquí para obtener la clave",
"misc": "otro",
"no_models_for_check": "No hay modelos disponibles para revisar (por ejemplo, modelos de conversación)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Agent invalide"
},
"model": {
"tooltip": "Actuellement, seuls les modèles qui prennent en charge les points de terminaison Anthropic sont disponibles pour la fonctionnalité Agent."
"supported_providers": "Fournisseurs pris en charge",
"tooltip": "Actuellement, seuls les modèles qui prennent en charge les points de terminaison Anthropic sont disponibles pour la fonctionnalité Agent.",
"view_providers": "Afficher les fournisseurs pris en charge"
},
"title": "Ajouter un agent",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Voir",
"docs_more_details": "Obtenir plus de détails",
"filter": {
"agent": "Prise en charge par un agent",
"all": "Tous les fournisseurs"
},
"filter_agent": "Fournisseurs pris en charge par l'agent de filtrage",
"get_api_key": "Cliquez ici pour obtenir une clé",
"misc": "autre",
"no_models_for_check": "Aucun modèle détectable (par exemple, modèle de chat)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "無効なエージェント"
},
"model": {
"tooltip": "現在、エージェント機能では、Anthropicエンドポイントをサポートするモデルのみが利用可能です。"
"supported_providers": "サポートされているプロバイダー",
"tooltip": "現在、エージェント機能では、Anthropicエンドポイントをサポートするモデルのみが利用可能です。",
"view_providers": "サポートされているプロバイダーを表示"
},
"title": "エージェントを追加",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "チェック",
"docs_more_details": "詳細を確認",
"filter": {
"agent": "エージェントサポート",
"all": "すべてのプロバイダー"
},
"filter_agent": "フィルターエージェント対応プロバイダー",
"get_api_key": "APIキーを取得",
"misc": "その他",
"no_models_for_check": "チェックするモデルがありません(例:会話モデル)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Agent inválido"
},
"model": {
"tooltip": "Atualmente, apenas modelos que suportam endpoints da Anthropic estão disponíveis para o recurso Agente."
"supported_providers": "Provedores Suportados",
"tooltip": "Atualmente, apenas modelos que suportam endpoints da Anthropic estão disponíveis para o recurso Agente.",
"view_providers": "Ver provedores suportados"
},
"title": "Adicionar Agente",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Verificar",
"docs_more_details": "Obter mais detalhes",
"filter": {
"agent": "Suportado por Agente",
"all": "Todos os Provedores"
},
"filter_agent": "Agente de Filtro - Provedores Suportados",
"get_api_key": "Clique aqui para obter a chave",
"misc": "outro",
"no_models_for_check": "Não há modelos disponíveis para verificação (por exemplo, modelos de conversa)",

View File

@ -7,7 +7,9 @@
"invalid_agent": "Недействительный агент"
},
"model": {
"tooltip": "В настоящее время для функции агента доступны только модели, поддерживающие конечные точки Anthropic."
"supported_providers": "Поддерживаемые поставщики",
"tooltip": "В настоящее время для функции агента доступны только модели, поддерживающие конечные точки Anthropic.",
"view_providers": "Просмотреть поддерживаемых поставщиков"
},
"title": "Добавить агента",
"type": {
@ -4508,6 +4510,11 @@
},
"docs_check": "Проверить",
"docs_more_details": "для получения дополнительной информации",
"filter": {
"agent": "Поддержка агента",
"all": "Все поставщики"
},
"filter_agent": "Поддерживаемые поставщики агента фильтрации",
"get_api_key": "Получить ключ API",
"misc": "другие",
"no_models_for_check": "Нет моделей для проверки (например, диалоговые модели)",

View File

@ -1,29 +1,26 @@
import AiProvider from '@renderer/aiCore'
import AnthropicProviderListPopover from '@renderer/components/AnthropicProviderListPopover'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import ModelSelector from '@renderer/components/ModelSelector'
import { isMac, isWin } from '@renderer/config/constant'
import { isEmbeddingModel, isRerankModel, isTextToImageModel } from '@renderer/config/models'
import { getProviderLogo } from '@renderer/config/providers'
import { useCodeTools } from '@renderer/hooks/useCodeTools'
import { useAllProviders, useProviders } from '@renderer/hooks/useProvider'
import { useProviders } from '@renderer/hooks/useProvider'
import { useTimer } from '@renderer/hooks/useTimer'
import { getProviderLabel } from '@renderer/i18n/label'
import { getProviderByModel } from '@renderer/services/AssistantService'
import { loggerService } from '@renderer/services/LoggerService'
import { getModelUniqId } from '@renderer/services/ModelService'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { setIsBunInstalled } from '@renderer/store/mcp'
import type { EndpointType, Model } from '@renderer/types'
import { getClaudeSupportedProviders } from '@renderer/utils/provider'
import type { TerminalConfig } from '@shared/config/constant'
import { codeTools, terminalApps } from '@shared/config/constant'
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
import { Alert, Avatar, Button, Checkbox, Input, Popover, Select, Space, Tooltip } from 'antd'
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
import { Alert, Button, Checkbox, Input, Select, Space, Tooltip } from 'antd'
import { Download, FolderOpen, Terminal, X } from 'lucide-react'
import type { FC } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Link } from 'react-router-dom'
import styled from 'styled-components'
import {
@ -40,7 +37,6 @@ const logger = loggerService.withContext('CodeToolsPage')
const CodeToolsPage: FC = () => {
const { t } = useTranslation()
const { providers } = useProviders()
const allProviders = useAllProviders()
const dispatch = useAppDispatch()
const isBunInstalled = useAppSelector((state) => state.mcp.isBunInstalled)
const {
@ -372,48 +368,7 @@ const CodeToolsPage: FC = () => {
<SettingsItem>
<div className="settings-label">
{t('code.model')}
{selectedCliTool === 'claude-code' && (
<Popover
content={
<div style={{ width: 200 }}>
<div style={{ marginBottom: 8, fontWeight: 500 }}>{t('code.supported_providers')}</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: 8
}}>
{getClaudeSupportedProviders(allProviders).map((provider) => {
return (
<Link
key={provider.id}
style={{
color: 'var(--color-text)',
display: 'flex',
alignItems: 'center',
gap: 4
}}
to={`/settings/provider?id=${provider.id}`}>
<ProviderLogo shape="square" src={getProviderLogo(provider.id)} size={20} />
{getProviderLabel(provider.id)}
<ArrowUpRight size={14} />
</Link>
)
})}
</div>
</div>
}
trigger="hover"
placement="right">
<HelpCircle
size={14}
style={{
color: 'var(--color-text-3)',
cursor: 'pointer'
}}
/>
</Popover>
)}
{selectedCliTool === 'claude-code' && <AnthropicProviderListPopover />}
</div>
<ModelSelector
providers={availableProviders}
@ -621,8 +576,4 @@ const BunInstallAlert = styled.div`
margin-bottom: 24px;
`
const ProviderLogo = styled(Avatar)`
border-radius: 4px;
`
export default CodeToolsPage

View File

@ -15,7 +15,7 @@ import { isSystemProvider } from '@renderer/types'
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
import type { MenuProps } from 'antd'
import { Button, Dropdown, Input, Tag } from 'antd'
import { GripVertical, PlusIcon, Search, UserPen } from 'lucide-react'
import { Check, Filter, GripVertical, PlusIcon, Search, UserPen } from 'lucide-react'
import type { FC } from 'react'
import { startTransition, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -42,6 +42,7 @@ const ProviderList: FC = () => {
const { t } = useTranslation()
const [searchText, setSearchText] = useState<string>('')
const [dragging, setDragging] = useState(false)
const [agentFilterEnabled, setAgentFilterEnabled] = useState(false)
const [providerLogos, setProviderLogos] = useState<Record<string, string>>({})
const listRef = useRef<DraggableVirtualListRef>(null)
@ -71,7 +72,16 @@ const ProviderList: FC = () => {
}, [providers])
useEffect(() => {
if (searchParams.get('id')) {
let shouldUpdate = false
const hasFilterParam = searchParams.get('filter') === 'agent'
// Handle filter param first - when filter is enabled, ignore id param
if (hasFilterParam) {
setAgentFilterEnabled(true)
searchParams.delete('filter')
searchParams.delete('id') // Clear id param when filter is enabled
shouldUpdate = true
} else if (searchParams.get('id')) {
const providerId = searchParams.get('id')
const provider = providers.find((p) => p.id === providerId)
if (provider) {
@ -89,6 +99,10 @@ const ProviderList: FC = () => {
setSelectedProvider(providers[0])
}
searchParams.delete('id')
shouldUpdate = true
}
if (shouldUpdate) {
setSearchParams(searchParams)
}
}, [providers, searchParams, setSearchParams, setSelectedProvider, setTimeoutTimer])
@ -282,6 +296,11 @@ const ProviderList: FC = () => {
return false
}
// Filter by agent support
if (agentFilterEnabled && !provider.anthropicApiHost) {
return false
}
const keywords = searchText.toLowerCase().split(/\s+/).filter(Boolean)
const isProviderMatch = matchKeywordsInProvider(keywords, provider)
const isModelMatch = provider.models.some((model) => matchKeywordsInModel(keywords, model))
@ -316,7 +335,34 @@ const ProviderList: FC = () => {
placeholder={t('settings.provider.search')}
value={searchText}
style={{ borderRadius: 'var(--list-item-border-radius)', height: 35 }}
suffix={<Search size={14} />}
prefix={<Search size={14} />}
suffix={
<Dropdown
menu={{
items: [
{
label: t('settings.provider.filter.all'),
key: 'all',
icon: agentFilterEnabled ? <CheckPlaceholder /> : <Check size={14} />,
onClick: () => setAgentFilterEnabled(false)
},
{
label: t('settings.provider.filter.agent'),
key: 'agent',
icon: agentFilterEnabled ? <Check size={14} /> : <CheckPlaceholder />,
onClick: () => setAgentFilterEnabled(true)
}
]
}}
trigger={['click']}>
<FilterButton>
<Filter
size={14}
className={agentFilterEnabled ? 'text-[var(--color-primary)]' : 'text-[var(--color-text-3)]'}
/>
</FilterButton>
</Dropdown>
}
onChange={(e) => setSearchText(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Escape') {
@ -457,4 +503,20 @@ const AddButtonWrapper = styled.div`
padding: 10px 8px;
`
const FilterButton = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 4px;
cursor: pointer;
`
const CheckPlaceholder = styled.span`
display: inline-block;
width: 14px;
height: 14px;
`
export default ProviderList

View File

@ -2,9 +2,11 @@ import { type AzureOpenAIProvider, type Provider, SystemProviderIds } from '@ren
import { describe, expect, it, vi } from 'vitest'
import {
getAnthropicSupportedProviders,
getClaudeSupportedProviders,
isAIGatewayProvider,
isAnthropicProvider,
isAnthropicSupportedProvider,
isAzureOpenAIProvider,
isCherryAIProvider,
isGeminiProvider,
@ -67,6 +69,26 @@ describe('provider utils', () => {
expect(getClaudeSupportedProviders(providers)).toEqual(providers.slice(0, 3))
})
it('filters Anthropic supported providers', () => {
const providers = [
createProvider({ id: 'anthropic-official', type: 'anthropic' }),
createProvider({ id: 'custom-host', anthropicApiHost: 'https://anthropic.local' }),
createProvider({ id: 'aihubmix' }),
createProvider({ id: 'other' })
]
expect(getAnthropicSupportedProviders(providers)).toEqual(providers.slice(0, 2))
})
it('checks Anthropic supported provider', () => {
expect(isAnthropicSupportedProvider(createProvider({ id: 'anthropic-official', type: 'anthropic' }))).toBe(true)
expect(
isAnthropicSupportedProvider(createProvider({ id: 'custom-host', anthropicApiHost: 'https://anthropic.local' }))
).toBe(true)
expect(isAnthropicSupportedProvider(createProvider({ id: 'aihubmix' }))).toBe(false)
expect(isAnthropicSupportedProvider(createProvider({ id: 'other' }))).toBe(false)
})
it('evaluates message array content support', () => {
expect(isSupportArrayContentProvider(createProvider())).toBe(true)

View File

@ -12,6 +12,14 @@ export const getClaudeSupportedProviders = (providers: Provider[]) => {
)
}
export const getAnthropicSupportedProviders = (providers: Provider[]) => {
return providers.filter(isAnthropicSupportedProvider)
}
export const isAnthropicSupportedProvider = (provider: Provider) => {
return provider.type === 'anthropic' || !!provider.anthropicApiHost
}
const NOT_SUPPORT_ARRAY_CONTENT_PROVIDERS = [
'deepseek',
'baichuan',