mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 22:52:08 +08:00
refactor: align create agent model selection with edit agent
This commit is contained in:
parent
84f2281506
commit
84bf94e2ff
@ -3,14 +3,14 @@ import ClaudeIcon from '@renderer/assets/images/models/claude.png'
|
||||
import { ErrorBoundary } from '@renderer/components/ErrorBoundary'
|
||||
import { TopView } from '@renderer/components/TopView'
|
||||
import { permissionModeCards } from '@renderer/config/agent'
|
||||
import { agentModelFilter, getModelLogoById } from '@renderer/config/models'
|
||||
import { useAgents } from '@renderer/hooks/agents/useAgents'
|
||||
import { useApiModels } from '@renderer/hooks/agents/useModels'
|
||||
import { useUpdateAgent } from '@renderer/hooks/agents/useUpdateAgent'
|
||||
import SelectAgentBaseModelButton from '@renderer/pages/home/components/SelectAgentBaseModelButton'
|
||||
import type {
|
||||
AddAgentForm,
|
||||
AgentEntity,
|
||||
AgentType,
|
||||
ApiModel,
|
||||
BaseAgentForm,
|
||||
PermissionMode,
|
||||
Tool,
|
||||
@ -65,7 +65,6 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
|
||||
const loadingRef = useRef(false)
|
||||
const { addAgent } = useAgents()
|
||||
const { updateAgent } = useUpdateAgent()
|
||||
const { models } = useApiModels({ providerType: 'anthropic' })
|
||||
const isEditing = (agent?: AgentWithTools) => agent !== undefined
|
||||
|
||||
const [form, setForm] = useState<BaseAgentForm>(() => buildAgentForm(agent))
|
||||
@ -199,32 +198,26 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
|
||||
}))
|
||||
}, [])
|
||||
|
||||
const modelOptions = useMemo(() => {
|
||||
return (models ?? [])
|
||||
.filter((m) =>
|
||||
agentModelFilter({
|
||||
id: m.id,
|
||||
provider: m.provider || '',
|
||||
name: m.name,
|
||||
group: ''
|
||||
})
|
||||
)
|
||||
.map((model) => ({
|
||||
value: model.id,
|
||||
label: (
|
||||
<OptionWrapper>
|
||||
<Avatar src={getModelLogoById(model.id)} size={24} />
|
||||
<span>{model.name}</span>
|
||||
</OptionWrapper>
|
||||
)
|
||||
}))
|
||||
}, [models])
|
||||
// Create a temporary agentBase object for SelectAgentBaseModelButton
|
||||
const tempAgentBase: AgentEntity = useMemo(
|
||||
() => ({
|
||||
id: agent?.id ?? 'temp-creating',
|
||||
type: form.type,
|
||||
name: form.name,
|
||||
model: form.model,
|
||||
accessible_paths: form.accessible_paths.length > 0 ? form.accessible_paths : ['/'],
|
||||
allowed_tools: form.allowed_tools ?? [],
|
||||
description: form.description,
|
||||
instructions: form.instructions,
|
||||
configuration: form.configuration,
|
||||
created_at: agent?.created_at ?? new Date().toISOString(),
|
||||
updated_at: agent?.updated_at ?? new Date().toISOString()
|
||||
}),
|
||||
[form, agent?.id, agent?.created_at, agent?.updated_at]
|
||||
)
|
||||
|
||||
const onModelChange = useCallback((value: string) => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
model: value
|
||||
}))
|
||||
const handleModelSelect = useCallback(async (model: ApiModel) => {
|
||||
setForm((prev) => ({ ...prev, model: model.id }))
|
||||
}, [])
|
||||
|
||||
const onCancel = () => {
|
||||
@ -336,7 +329,7 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
|
||||
afterClose={onClose}
|
||||
transitionName="animation-move-down"
|
||||
centered
|
||||
width={680}
|
||||
width={500}
|
||||
footer={null}>
|
||||
<StyledForm onSubmit={onSubmit}>
|
||||
<FormContent>
|
||||
@ -363,17 +356,20 @@ const PopupContainer: React.FC<Props> = ({ agent, afterSubmit, resolve }) => {
|
||||
<Label>
|
||||
{t('common.model')} <RequiredMark>*</RequiredMark>
|
||||
</Label>
|
||||
<Select
|
||||
value={form.model || undefined}
|
||||
onChange={onModelChange}
|
||||
options={modelOptions}
|
||||
placeholder={t('common.placeholders.select.model')}
|
||||
style={{ width: '100%' }}
|
||||
showSearch
|
||||
filterOption={(input, option) => {
|
||||
const label = option?.label as any
|
||||
return label?.props?.children?.[1]?.toLowerCase().includes(input.toLowerCase()) || false
|
||||
<SelectAgentBaseModelButton
|
||||
agentBase={tempAgentBase}
|
||||
onSelect={handleModelSelect}
|
||||
fontSize={14}
|
||||
avatarSize={24}
|
||||
iconSize={16}
|
||||
buttonStyle={{
|
||||
padding: '8px 12px',
|
||||
width: '100%',
|
||||
border: '1px solid var(--color-border)',
|
||||
borderRadius: 6,
|
||||
height: 'auto'
|
||||
}}
|
||||
containerClassName="flex items-center justify-between w-full"
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
|
||||
@ -4,25 +4,56 @@ import { agentModelFilter } from '@renderer/config/models'
|
||||
import { useApiModel } from '@renderer/hooks/agents/useModel'
|
||||
import { getProviderNameById } from '@renderer/services/ProviderService'
|
||||
import type { AgentBaseWithId, ApiModel } from '@renderer/types'
|
||||
import { isAgentSessionEntity } from '@renderer/types'
|
||||
import { isAgentEntity } from '@renderer/types'
|
||||
import { getModelFilterByAgentType } from '@renderer/utils/agentSession'
|
||||
import { apiModelAdapter } from '@renderer/utils/model'
|
||||
import type { ButtonProps } from 'antd'
|
||||
import { Button } from 'antd'
|
||||
import { ChevronsUpDown } from 'lucide-react'
|
||||
import type { FC } from 'react'
|
||||
import type { CSSProperties, FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface Props {
|
||||
agentBase: AgentBaseWithId
|
||||
onSelect: (model: ApiModel) => Promise<void>
|
||||
isDisabled?: boolean
|
||||
/** Custom className for the button */
|
||||
className?: string
|
||||
/** Custom inline styles for the button (merged with default styles) */
|
||||
buttonStyle?: CSSProperties
|
||||
/** Custom button size */
|
||||
buttonSize?: ButtonProps['size']
|
||||
/** Custom avatar size */
|
||||
avatarSize?: number
|
||||
/** Custom font size */
|
||||
fontSize?: number
|
||||
/** Custom icon size */
|
||||
iconSize?: number
|
||||
/** Custom className for the inner container (e.g., for justify-between) */
|
||||
containerClassName?: string
|
||||
}
|
||||
|
||||
const SelectAgentBaseModelButton: FC<Props> = ({ agentBase: agent, onSelect, isDisabled }) => {
|
||||
const SelectAgentBaseModelButton: FC<Props> = ({
|
||||
agentBase: agent,
|
||||
onSelect,
|
||||
isDisabled,
|
||||
className,
|
||||
buttonStyle,
|
||||
buttonSize = 'small',
|
||||
avatarSize = 20,
|
||||
fontSize = 12,
|
||||
iconSize = 14,
|
||||
containerClassName
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const model = useApiModel({ id: agent?.model })
|
||||
|
||||
const apiFilter = isAgentEntity(agent) ? getModelFilterByAgentType(agent.type) : undefined
|
||||
const apiFilter = isAgentEntity(agent)
|
||||
? getModelFilterByAgentType(agent.type)
|
||||
: isAgentSessionEntity(agent)
|
||||
? getModelFilterByAgentType(agent.agent_type)
|
||||
: undefined
|
||||
|
||||
if (!agent) return null
|
||||
|
||||
@ -35,20 +66,31 @@ const SelectAgentBaseModelButton: FC<Props> = ({ agentBase: agent, onSelect, isD
|
||||
|
||||
const providerName = model?.provider ? getProviderNameById(model.provider) : model?.provider_name
|
||||
|
||||
// Merge default styles with custom styles
|
||||
const mergedStyle: CSSProperties = {
|
||||
borderRadius: 20,
|
||||
fontSize,
|
||||
padding: 2,
|
||||
...buttonStyle
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
size={buttonSize}
|
||||
type="text"
|
||||
style={{ borderRadius: 20, fontSize: 12, padding: 2 }}
|
||||
className={className}
|
||||
style={mergedStyle}
|
||||
onClick={onSelectModel}
|
||||
disabled={isDisabled}>
|
||||
<div className="flex items-center gap-1.5 overflow-x-hidden">
|
||||
<ModelAvatar model={model ? apiModelAdapter(model) : undefined} size={20} />
|
||||
<span className="truncate text-[var(--color-text)]">
|
||||
{model ? model.name : t('button.select_model')} {providerName ? ' | ' + providerName : ''}
|
||||
</span>
|
||||
<div className={containerClassName || 'flex w-full items-center gap-1.5'}>
|
||||
<div className="flex flex-1 items-center gap-1.5 overflow-x-hidden">
|
||||
<ModelAvatar model={model ? apiModelAdapter(model) : undefined} size={avatarSize} />
|
||||
<span className="truncate text-[var(--color-text)]">
|
||||
{model ? model.name : t('button.select_model')} {providerName ? ' | ' + providerName : ''}
|
||||
</span>
|
||||
</div>
|
||||
<ChevronsUpDown size={iconSize} color="var(--color-icon)" />
|
||||
</div>
|
||||
<ChevronsUpDown size={14} color="var(--color-icon)" />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user