feat: Add new model type for reasoning models & reasoning_effort setting (#992)
This commit is contained in:
parent
9024d48938
commit
9acae0a728
@ -1,4 +1,4 @@
|
|||||||
import { isEmbeddingModel, isVisionModel, isWebSearchModel } from '@renderer/config/models'
|
import { isEmbeddingModel, isReasoningModel, isVisionModel, isWebSearchModel } from '@renderer/config/models'
|
||||||
import { Model } from '@renderer/types'
|
import { Model } from '@renderer/types'
|
||||||
import { isFreeModel } from '@renderer/utils'
|
import { isFreeModel } from '@renderer/utils'
|
||||||
import { Tag } from 'antd'
|
import { Tag } from 'antd'
|
||||||
@ -29,6 +29,11 @@ const ModelTags: FC<ModelTagsProps> = ({ model, showFree = true }) => {
|
|||||||
{t('models.embedding')}
|
{t('models.embedding')}
|
||||||
</Tag>
|
</Tag>
|
||||||
)}
|
)}
|
||||||
|
{isReasoningModel(model) && (
|
||||||
|
<Tag color="blue" style={{ marginLeft: 10 }}>
|
||||||
|
{t('models.reasoning')}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -156,6 +156,8 @@ export const VISION_REGEX = new RegExp(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const TEXT_TO_IMAGE_REGEX = /flux|diffusion|stabilityai|sd-|dall|cogview|janus/i
|
export const TEXT_TO_IMAGE_REGEX = /flux|diffusion|stabilityai|sd-|dall|cogview|janus/i
|
||||||
|
export const REASONING_REGEX = /^(o\d+(?:-[\w-]+)?|.*\breasoner\b.*|.*-[rR]\d+.*)$/i
|
||||||
|
|
||||||
export const EMBEDDING_REGEX = /(?:^text-|embed|rerank|davinci|babbage|bge-|e5-|LLM2Vec|retrieval|uae-|gte-|jina)/i
|
export const EMBEDDING_REGEX = /(?:^text-|embed|rerank|davinci|babbage|bge-|e5-|LLM2Vec|retrieval|uae-|gte-|jina)/i
|
||||||
export const NOT_SUPPORTED_REGEX = /(?:^tts|rerank|whisper|speech)/i
|
export const NOT_SUPPORTED_REGEX = /(?:^tts|rerank|whisper|speech)/i
|
||||||
|
|
||||||
@ -1127,6 +1129,14 @@ export function isVisionModel(model: Model): boolean {
|
|||||||
return VISION_REGEX.test(model.id) || model.type?.includes('vision') || false
|
return VISION_REGEX.test(model.id) || model.type?.includes('vision') || false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isReasoningModel(model: Model): boolean {
|
||||||
|
if (!model) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return REASONING_REGEX.test(model.id) || model.type?.includes('reasoning') || false
|
||||||
|
}
|
||||||
|
|
||||||
export function isSupportedModel(model: OpenAI.Models.Model): boolean {
|
export function isSupportedModel(model: OpenAI.Models.Model): boolean {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -40,6 +40,11 @@
|
|||||||
"save.success": "Saved successfully",
|
"save.success": "Saved successfully",
|
||||||
"save.title": "Save to agent",
|
"save.title": "Save to agent",
|
||||||
"search": "Search assistants...",
|
"search": "Search assistants...",
|
||||||
|
"settings.reasoning_effort": "Reasoning effort",
|
||||||
|
"settings.reasoning_effort.tip": "Only supports reasoning models",
|
||||||
|
"settings.reasoning_effort.low": "low",
|
||||||
|
"settings.reasoning_effort.medium": "medium",
|
||||||
|
"settings.reasoning_effort.high": "high",
|
||||||
"settings.auto_reset_model": "Auto Reset Model",
|
"settings.auto_reset_model": "Auto Reset Model",
|
||||||
"settings.auto_reset_model.tip": "Automatically reset the model when a new topic is created.",
|
"settings.auto_reset_model.tip": "Automatically reset the model when a new topic is created.",
|
||||||
"settings.default_model": "Default Model",
|
"settings.default_model": "Default Model",
|
||||||
@ -640,12 +645,14 @@
|
|||||||
"select": "Select Model Types",
|
"select": "Select Model Types",
|
||||||
"text": "Text",
|
"text": "Text",
|
||||||
"vision": "Vision",
|
"vision": "Vision",
|
||||||
"embedding": "Embedding"
|
"embedding": "Embedding",
|
||||||
|
"reasoning": "Reasoning"
|
||||||
},
|
},
|
||||||
"all": "All",
|
"all": "All",
|
||||||
"vision": "Vision",
|
"vision": "Vision",
|
||||||
"websearch": "WebSearch",
|
"websearch": "WebSearch",
|
||||||
"free": "Free",
|
"free": "Free",
|
||||||
|
"reasoning": "Reasoning",
|
||||||
"embedding": "Embedding",
|
"embedding": "Embedding",
|
||||||
"embedding_model": "Embedding Model",
|
"embedding_model": "Embedding Model",
|
||||||
"embedding_model_tooltip": "Add in Settings->Model Provider->Manage",
|
"embedding_model_tooltip": "Add in Settings->Model Provider->Manage",
|
||||||
|
|||||||
@ -625,12 +625,14 @@
|
|||||||
"select": "モデルタイプを選択",
|
"select": "モデルタイプを選択",
|
||||||
"text": "テキスト",
|
"text": "テキスト",
|
||||||
"vision": "画像",
|
"vision": "画像",
|
||||||
"embedding": "埋め込み"
|
"embedding": "埋め込み",
|
||||||
|
"reasoning": "推論"
|
||||||
},
|
},
|
||||||
"all": "すべて",
|
"all": "すべて",
|
||||||
"vision": "画像モデル",
|
"vision": "画像モデル",
|
||||||
"websearch": "ウェブ検索モデル",
|
"websearch": "ウェブ検索モデル",
|
||||||
"free": "無料モデル",
|
"free": "無料モデル",
|
||||||
|
"reasoning": "推論モデル",
|
||||||
"embedding": "埋め込みモデル",
|
"embedding": "埋め込みモデル",
|
||||||
"embedding_model": "埋め込みモデル",
|
"embedding_model": "埋め込みモデル",
|
||||||
"embedding_model_tooltip": "設定->モデルサービス->管理で追加",
|
"embedding_model_tooltip": "設定->モデルサービス->管理で追加",
|
||||||
|
|||||||
@ -637,12 +637,14 @@
|
|||||||
"select": "Выберите тип модели",
|
"select": "Выберите тип модели",
|
||||||
"text": "Текст",
|
"text": "Текст",
|
||||||
"vision": "Изображение",
|
"vision": "Изображение",
|
||||||
"embedding": "Встраиваемые"
|
"embedding": "Встраиваемые",
|
||||||
|
"reasoning": "Рассуждение"
|
||||||
},
|
},
|
||||||
"all": "Все",
|
"all": "Все",
|
||||||
"vision": "Визуальные модели",
|
"vision": "Визуальные модели",
|
||||||
"websearch": "Веб-поисковые модели",
|
"websearch": "Веб-поисковые модели",
|
||||||
"free": "Бесплатные модели",
|
"free": "Бесплатные модели",
|
||||||
|
"reasoning": "Модели рассуждения",
|
||||||
"embedding": "Встраиваемые модели",
|
"embedding": "Встраиваемые модели",
|
||||||
"embedding_model": "Встраиваемые модели",
|
"embedding_model": "Встраиваемые модели",
|
||||||
"embedding_model_tooltip": "Добавьте в настройки->модель сервиса->управление",
|
"embedding_model_tooltip": "Добавьте в настройки->модель сервиса->управление",
|
||||||
|
|||||||
@ -40,6 +40,11 @@
|
|||||||
"save.success": "保存成功",
|
"save.success": "保存成功",
|
||||||
"save.title": "保存到智能体",
|
"save.title": "保存到智能体",
|
||||||
"search": "搜索助手",
|
"search": "搜索助手",
|
||||||
|
"settings.reasoning_effort": "思维链长度",
|
||||||
|
"settings.reasoning_effort.tip": "该设置仅支持推理模型",
|
||||||
|
"settings.reasoning_effort.low": "短",
|
||||||
|
"settings.reasoning_effort.medium": "中",
|
||||||
|
"settings.reasoning_effort.high": "长",
|
||||||
"settings.auto_reset_model": "自动重置模型",
|
"settings.auto_reset_model": "自动重置模型",
|
||||||
"settings.auto_reset_model.tip": "创建新话题时自动重置模型",
|
"settings.auto_reset_model.tip": "创建新话题时自动重置模型",
|
||||||
"settings.default_model": "默认模型",
|
"settings.default_model": "默认模型",
|
||||||
@ -627,12 +632,14 @@
|
|||||||
"select": "选择模型类型",
|
"select": "选择模型类型",
|
||||||
"text": "文本",
|
"text": "文本",
|
||||||
"vision": "图像",
|
"vision": "图像",
|
||||||
"embedding": "嵌入"
|
"embedding": "嵌入",
|
||||||
|
"reasoning": "推理"
|
||||||
},
|
},
|
||||||
"all": "全部",
|
"all": "全部",
|
||||||
"vision": "视觉模型",
|
"vision": "视觉模型",
|
||||||
"websearch": "联网模型",
|
"websearch": "联网模型",
|
||||||
"free": "免费模型",
|
"free": "免费模型",
|
||||||
|
"reasoning": "推理模型",
|
||||||
"embedding": "嵌入模型",
|
"embedding": "嵌入模型",
|
||||||
"embedding_model": "嵌入模型",
|
"embedding_model": "嵌入模型",
|
||||||
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
||||||
|
|||||||
@ -40,6 +40,11 @@
|
|||||||
"save.success": "儲存成功",
|
"save.success": "儲存成功",
|
||||||
"save.title": "儲存到智能體",
|
"save.title": "儲存到智能體",
|
||||||
"search": "搜尋助手...",
|
"search": "搜尋助手...",
|
||||||
|
"settings.reasoning_effort": "思維鏈長度",
|
||||||
|
"settings.reasoning_effort.tip": "該設置僅支持推理模型",
|
||||||
|
"settings.reasoning_effort.low": "短",
|
||||||
|
"settings.reasoning_effort.medium": "中",
|
||||||
|
"settings.reasoning_effort.high": "長",
|
||||||
"settings.auto_reset_model": "自動重置模型",
|
"settings.auto_reset_model": "自動重置模型",
|
||||||
"settings.auto_reset_model.tip": "每次新的話題時自動重置模型",
|
"settings.auto_reset_model.tip": "每次新的話題時自動重置模型",
|
||||||
"settings.default_model": "預設模型",
|
"settings.default_model": "預設模型",
|
||||||
@ -626,12 +631,14 @@
|
|||||||
"select": "選擇模型類型",
|
"select": "選擇模型類型",
|
||||||
"text": "文字",
|
"text": "文字",
|
||||||
"vision": "圖像",
|
"vision": "圖像",
|
||||||
"embedding": "嵌入"
|
"embedding": "嵌入",
|
||||||
|
"reasoning": "推理"
|
||||||
},
|
},
|
||||||
"all": "全部",
|
"all": "全部",
|
||||||
"vision": "視覺模型",
|
"vision": "視覺模型",
|
||||||
"websearch": "網路搜索模型",
|
"websearch": "網路搜索模型",
|
||||||
"free": "免費模型",
|
"free": "免費模型",
|
||||||
|
"reasoning": "推理模型",
|
||||||
"embedding": "嵌入模型",
|
"embedding": "嵌入模型",
|
||||||
"embedding_model": "嵌入模型",
|
"embedding_model": "嵌入模型",
|
||||||
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
"embedding_model_tooltip": "在设置->模型服务中点击管理按钮添加",
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import SelectModelPopup from '@renderer/components/Popups/SelectModelPopup'
|
|||||||
import { DEFAULT_CONTEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
import { DEFAULT_CONTEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
|
||||||
import { SettingRow } from '@renderer/pages/settings'
|
import { SettingRow } from '@renderer/pages/settings'
|
||||||
import { Assistant, AssistantSettingCustomParameters, AssistantSettings } from '@renderer/types'
|
import { Assistant, AssistantSettingCustomParameters, AssistantSettings } from '@renderer/types'
|
||||||
import { Button, Col, Divider, Input, InputNumber, Row, Select, Slider, Switch, Tooltip } from 'antd'
|
import { Button, Col, Divider, Input, InputNumber, Radio, Row, Select, Slider, Switch, Tooltip } from 'antd'
|
||||||
import { isNull } from 'lodash'
|
import { isNull } from 'lodash'
|
||||||
import { FC, useEffect, useRef, useState } from 'react'
|
import { FC, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -23,6 +23,7 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
|
|||||||
const [enableMaxTokens, setEnableMaxTokens] = useState(assistant?.settings?.enableMaxTokens ?? false)
|
const [enableMaxTokens, setEnableMaxTokens] = useState(assistant?.settings?.enableMaxTokens ?? false)
|
||||||
const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0)
|
const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0)
|
||||||
const [autoResetModel, setAutoResetModel] = useState(assistant?.settings?.autoResetModel ?? false)
|
const [autoResetModel, setAutoResetModel] = useState(assistant?.settings?.autoResetModel ?? false)
|
||||||
|
const [reasoningEffort, setReasoningEffort] = useState(assistant?.settings?.reasoning_effort ?? 'medium')
|
||||||
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
|
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
|
||||||
const [defaultModel, setDefaultModel] = useState(assistant?.defaultModel)
|
const [defaultModel, setDefaultModel] = useState(assistant?.defaultModel)
|
||||||
const [topP, setTopP] = useState(assistant?.settings?.topP ?? 1)
|
const [topP, setTopP] = useState(assistant?.settings?.topP ?? 1)
|
||||||
@ -43,6 +44,10 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onReasoningEffortChange = (value) => {
|
||||||
|
updateAssistantSettings({ reasoning_effort: value })
|
||||||
|
}
|
||||||
|
|
||||||
const onContextCountChange = (value) => {
|
const onContextCountChange = (value) => {
|
||||||
if (!isNaN(value as number)) {
|
if (!isNaN(value as number)) {
|
||||||
updateAssistantSettings({ contextCount: value })
|
updateAssistantSettings({ contextCount: value })
|
||||||
@ -384,6 +389,26 @@ const AssistantModelSettings: FC<Props> = ({ assistant, updateAssistant, updateA
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<Divider style={{ margin: '10px 0' }} />
|
<Divider style={{ margin: '10px 0' }} />
|
||||||
|
<SettingRow style={{ minHeight: 30 }}>
|
||||||
|
<Label>
|
||||||
|
{t('assistants.settings.reasoning_effort')}{' '}
|
||||||
|
<Tooltip title={t('assistants.settings.reasoning_effort.tip')}>
|
||||||
|
<QuestionIcon />
|
||||||
|
</Tooltip>
|
||||||
|
</Label>
|
||||||
|
<Radio.Group
|
||||||
|
value={reasoningEffort}
|
||||||
|
buttonStyle="solid"
|
||||||
|
onChange={(e) => {
|
||||||
|
setReasoningEffort(e.target.value)
|
||||||
|
onReasoningEffortChange(e.target.value)
|
||||||
|
}}>
|
||||||
|
<Radio.Button value="low">{t('assistants.settings.reasoning_effort.low')}</Radio.Button>
|
||||||
|
<Radio.Button value="medium">{t('assistants.settings.reasoning_effort.medium')}</Radio.Button>
|
||||||
|
<Radio.Button value="high">{t('assistants.settings.reasoning_effort.high')}</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
</SettingRow>
|
||||||
|
<Divider style={{ margin: '10px 0' }} />
|
||||||
<SettingRow style={{ minHeight: 30 }}>
|
<SettingRow style={{ minHeight: 30 }}>
|
||||||
<Label>{t('models.custom_parameters')}</Label>
|
<Label>{t('models.custom_parameters')}</Label>
|
||||||
<Button icon={<PlusOutlined />} onClick={onAddCustomParameter}>
|
<Button icon={<PlusOutlined />} onClick={onAddCustomParameter}>
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import ModelTags from '@renderer/components/ModelTags'
|
import ModelTags from '@renderer/components/ModelTags'
|
||||||
import OAuthButton from '@renderer/components/OAuth/OAuthButton'
|
import OAuthButton from '@renderer/components/OAuth/OAuthButton'
|
||||||
import { EMBEDDING_REGEX, getModelLogo, VISION_REGEX } from '@renderer/config/models'
|
import { EMBEDDING_REGEX, getModelLogo, REASONING_REGEX, VISION_REGEX } from '@renderer/config/models'
|
||||||
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
import { PROVIDER_CONFIG } from '@renderer/config/providers'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useAssistants, useDefaultModel } from '@renderer/hooks/useAssistant'
|
import { useAssistants, useDefaultModel } from '@renderer/hooks/useAssistant'
|
||||||
@ -187,7 +187,8 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
|||||||
onChange={(types) => onUpdateModelTypes(model, types as ModelType[])}
|
onChange={(types) => onUpdateModelTypes(model, types as ModelType[])}
|
||||||
options={[
|
options={[
|
||||||
{ label: t('models.type.vision'), value: 'vision', disabled: VISION_REGEX.test(model.id) },
|
{ label: t('models.type.vision'), value: 'vision', disabled: VISION_REGEX.test(model.id) },
|
||||||
{ label: t('models.type.embedding'), value: 'embedding', disabled: EMBEDDING_REGEX.test(model.id) }
|
{ label: t('models.type.embedding'), value: 'embedding', disabled: EMBEDDING_REGEX.test(model.id) },
|
||||||
|
{ label: t('models.type.reasoning'), value: 'reasoning', disabled: REASONING_REGEX.test(model.id) }
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { getOpenAIWebSearchParams, isSupportedModel, isVisionModel } from '@renderer/config/models'
|
import { getOpenAIWebSearchParams, isReasoningModel, isSupportedModel, isVisionModel } from '@renderer/config/models'
|
||||||
import { getStoreSetting } from '@renderer/hooks/useSettings'
|
import { getStoreSetting } from '@renderer/hooks/useSettings'
|
||||||
import i18n from '@renderer/i18n'
|
import i18n from '@renderer/i18n'
|
||||||
import { getAssistantSettings, getDefaultModel, getTopNamingModel } from '@renderer/services/AssistantService'
|
import { getAssistantSettings, getDefaultModel, getTopNamingModel } from '@renderer/services/AssistantService'
|
||||||
@ -118,13 +118,7 @@ export default class OpenAIProvider extends BaseProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getTemperature(assistant: Assistant, model: Model) {
|
private getTemperature(assistant: Assistant, model: Model) {
|
||||||
if (model.id.startsWith('o1') || model.id.startsWith('o3')) {
|
if (isReasoningModel(model)) return undefined
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.provider === 'deepseek' && model.id === 'deepseek-reasoner') {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return assistant?.settings?.temperature
|
return assistant?.settings?.temperature
|
||||||
}
|
}
|
||||||
@ -141,6 +135,18 @@ export default class OpenAIProvider extends BaseProvider {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getTopP(assistant: Assistant, model: Model) {
|
||||||
|
if (isReasoningModel(model)) return undefined
|
||||||
|
|
||||||
|
return assistant?.settings?.topP
|
||||||
|
}
|
||||||
|
|
||||||
|
private getReasoningEffort(assistant: Assistant, model: Model) {
|
||||||
|
if (isReasoningModel(model)) return assistant?.settings?.reasoning_effort
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
async completions({ messages, assistant, onChunk, onFilterMessages }: CompletionsParams): Promise<void> {
|
async completions({ messages, assistant, onChunk, onFilterMessages }: CompletionsParams): Promise<void> {
|
||||||
const defaultModel = getDefaultModel()
|
const defaultModel = getDefaultModel()
|
||||||
const model = assistant.model || defaultModel
|
const model = assistant.model || defaultModel
|
||||||
@ -182,10 +188,11 @@ export default class OpenAIProvider extends BaseProvider {
|
|||||||
Boolean
|
Boolean
|
||||||
) as ChatCompletionMessageParam[],
|
) as ChatCompletionMessageParam[],
|
||||||
temperature: this.getTemperature(assistant, model),
|
temperature: this.getTemperature(assistant, model),
|
||||||
top_p: assistant?.settings?.topP,
|
top_p: this.getTopP(assistant, model),
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
keep_alive: this.keepAliveTime,
|
keep_alive: this.keepAliveTime,
|
||||||
stream: isSupportStreamOutput(),
|
stream: isSupportStreamOutput(),
|
||||||
|
reasoning_effort: this.getReasoningEffort(assistant, model),
|
||||||
...(assistant.enableWebSearch ? getOpenAIWebSearchParams(model) : {}),
|
...(assistant.enableWebSearch ? getOpenAIWebSearchParams(model) : {}),
|
||||||
...this.getProviderSpecificParameters(model),
|
...this.getProviderSpecificParameters(model),
|
||||||
...this.getCustomParameters(assistant)
|
...this.getCustomParameters(assistant)
|
||||||
|
|||||||
@ -38,6 +38,7 @@ export type AssistantSettings = {
|
|||||||
defaultModel?: Model
|
defaultModel?: Model
|
||||||
autoResetModel: boolean
|
autoResetModel: boolean
|
||||||
customParameters?: AssistantSettingCustomParameters[]
|
customParameters?: AssistantSettingCustomParameters[]
|
||||||
|
reasoning_effort?: 'low' | 'medium' | 'high'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Agent = Omit<Assistant, 'model'>
|
export type Agent = Omit<Assistant, 'model'>
|
||||||
@ -107,7 +108,7 @@ export type Provider = {
|
|||||||
|
|
||||||
export type ProviderType = 'openai' | 'anthropic' | 'gemini' | 'qwenlm' | 'azure-openai'
|
export type ProviderType = 'openai' | 'anthropic' | 'gemini' | 'qwenlm' | 'azure-openai'
|
||||||
|
|
||||||
export type ModelType = 'text' | 'vision' | 'embedding'
|
export type ModelType = 'text' | 'vision' | 'embedding' | 'reasoning'
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
id: string
|
id: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user