mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 01:20:01 +08:00
feat(AgentModal): add dynamic model options from API
Fetch model options from API instead of using mocked data Display provider label for model options
This commit is contained in:
parent
825b5e1be4
commit
ae35d689ec
@ -18,7 +18,10 @@ import {
|
|||||||
} from '@heroui/react'
|
} from '@heroui/react'
|
||||||
import { loggerService } from '@logger'
|
import { loggerService } from '@logger'
|
||||||
import ClaudeIcon from '@renderer/assets/images/models/claude.png'
|
import ClaudeIcon from '@renderer/assets/images/models/claude.png'
|
||||||
|
import { getModelLogo } from '@renderer/config/models'
|
||||||
import { useAgents } from '@renderer/hooks/agents/useAgents'
|
import { useAgents } from '@renderer/hooks/agents/useAgents'
|
||||||
|
import { useModels } from '@renderer/hooks/agents/useModels'
|
||||||
|
import { getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { AddAgentForm, AgentEntity, AgentType, BaseAgentForm, isAgentType, UpdateAgentForm } from '@renderer/types'
|
import { AddAgentForm, AgentEntity, AgentType, BaseAgentForm, isAgentType, UpdateAgentForm } from '@renderer/types'
|
||||||
import { ChangeEvent, FormEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { ChangeEvent, FormEvent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -27,19 +30,33 @@ import { ErrorBoundary } from '../../ErrorBoundary'
|
|||||||
|
|
||||||
const logger = loggerService.withContext('AddAgentPopup')
|
const logger = loggerService.withContext('AddAgentPopup')
|
||||||
|
|
||||||
interface Option {
|
interface BaseOption {
|
||||||
|
type: 'type' | 'model'
|
||||||
key: string
|
key: string
|
||||||
label: string
|
label: string
|
||||||
// img src
|
// img src
|
||||||
avatar: string
|
avatar: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AgentTypeOption extends Option {
|
interface AgentTypeOption extends BaseOption {
|
||||||
|
type: 'type'
|
||||||
key: AgentEntity['type']
|
key: AgentEntity['type']
|
||||||
name: AgentEntity['name']
|
name: AgentEntity['name']
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModelOption = Option
|
// function isAgentTypeOption(option: BaseOption): option is AgentTypeOption {
|
||||||
|
// return option.type === 'type'
|
||||||
|
// }
|
||||||
|
|
||||||
|
interface ModelOption extends BaseOption {
|
||||||
|
providerId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function isModelOption(option: BaseOption): option is ModelOption {
|
||||||
|
return option.type === 'model'
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option = AgentTypeOption | ModelOption
|
||||||
|
|
||||||
const buildAgentForm = (existing?: AgentEntity): BaseAgentForm => ({
|
const buildAgentForm = (existing?: AgentEntity): BaseAgentForm => ({
|
||||||
type: existing?.type ?? 'claude-code',
|
type: existing?.type ?? 'claude-code',
|
||||||
@ -84,6 +101,8 @@ export const AgentModal: React.FC<Props> = ({ agent, trigger, isOpen: _isOpen, o
|
|||||||
const loadingRef = useRef(false)
|
const loadingRef = useRef(false)
|
||||||
// const { setTimeoutTimer } = useTimer()
|
// const { setTimeoutTimer } = useTimer()
|
||||||
const { addAgent, updateAgent } = useAgents()
|
const { addAgent, updateAgent } = useAgents()
|
||||||
|
// hard-coded. We only support anthropic for now.
|
||||||
|
const { models } = useModels({ providerType: 'anthropic' })
|
||||||
const isEditing = (agent?: AgentEntity) => agent !== undefined
|
const isEditing = (agent?: AgentEntity) => agent !== undefined
|
||||||
|
|
||||||
const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
|
const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
|
||||||
@ -107,7 +126,7 @@ export const AgentModal: React.FC<Props> = ({ agent, trigger, isOpen: _isOpen, o
|
|||||||
return (
|
return (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Avatar src={option.avatar} className="h-5 w-5" />
|
<Avatar src={option.avatar} className="h-5 w-5" />
|
||||||
{option.label}
|
{option.label} {isModelOption(option) && option.providerId && `| ${getProviderLabel(option.providerId)}`}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -126,6 +145,7 @@ export const AgentModal: React.FC<Props> = ({ agent, trigger, isOpen: _isOpen, o
|
|||||||
() =>
|
() =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
type: 'type',
|
||||||
key: 'claude-code',
|
key: 'claude-code',
|
||||||
label: 'Claude Code',
|
label: 'Claude Code',
|
||||||
name: 'Claude Code',
|
name: 'Claude Code',
|
||||||
@ -189,14 +209,14 @@ export const AgentModal: React.FC<Props> = ({ agent, trigger, isOpen: _isOpen, o
|
|||||||
|
|
||||||
const modelOptions = useMemo(() => {
|
const modelOptions = useMemo(() => {
|
||||||
// mocked data. not final version
|
// mocked data. not final version
|
||||||
return [
|
return (models ?? []).map((model) => ({
|
||||||
{
|
type: 'model',
|
||||||
key: 'claude-4-sonnet',
|
key: model.id,
|
||||||
label: 'Claude 4 Sonnet',
|
label: model.name,
|
||||||
avatar: ClaudeIcon
|
avatar: getModelLogo(model.id),
|
||||||
}
|
providerId: model.provider
|
||||||
] satisfies ModelOption[]
|
})) satisfies ModelOption[]
|
||||||
}, [])
|
}, [models])
|
||||||
|
|
||||||
const onModelChange = useCallback((e: ChangeEvent<HTMLSelectElement>) => {
|
const onModelChange = useCallback((e: ChangeEvent<HTMLSelectElement>) => {
|
||||||
setForm((prev) => ({
|
setForm((prev) => ({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user