mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 20:12:38 +08:00
refactor(assistant): enhance assistant creation by automatically adding default topics; streamline default assistant handling
This commit is contained in:
parent
cb1fcf7d2d
commit
d41f175a05
@ -1,5 +1,4 @@
|
||||
import { db } from '@renderer/databases'
|
||||
import { getDefaultTopic } from '@renderer/services/AssistantService'
|
||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import {
|
||||
addAssistant,
|
||||
@ -22,7 +21,10 @@ export function useAssistants() {
|
||||
return {
|
||||
assistants,
|
||||
updateAssistants: (assistants: Assistant[]) => dispatch(updateAssistants(assistants)),
|
||||
addAssistant: (assistant: Assistant) => dispatch(addAssistant(assistant)),
|
||||
addAssistant: (assistant: Assistant) => {
|
||||
dispatch(addAssistant(assistant))
|
||||
dispatch(topicsActions.addDefaultTopic({ assistantId: assistant.id }))
|
||||
},
|
||||
removeAssistant: (id: string) => {
|
||||
dispatch(removeAssistant({ id }))
|
||||
// Remove all topics for this assistant
|
||||
@ -85,24 +87,15 @@ export function useTopicsForAssistant(assistantId: string) {
|
||||
return useAppSelector((state) => selectTopicsForAssistant(state, assistantId))
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认助手模板
|
||||
*/
|
||||
export function useDefaultAssistant() {
|
||||
const defaultAssistant = useAppSelector((state) => state.assistants.defaultAssistant)
|
||||
const topics = useTopicsForAssistant(defaultAssistant.id)
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
// Ensure default assistant has at least one topic
|
||||
const finalTopics = useMemo(() => {
|
||||
if (topics.length > 0) {
|
||||
return topics
|
||||
}
|
||||
return [getDefaultTopic(defaultAssistant.id)]
|
||||
}, [topics, defaultAssistant.id])
|
||||
|
||||
return {
|
||||
defaultAssistant: {
|
||||
...defaultAssistant,
|
||||
topics: finalTopics
|
||||
},
|
||||
defaultAssistant,
|
||||
updateDefaultAssistant: (assistant: Assistant) => dispatch(updateDefaultAssistant({ assistant }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { DEFAULT_CONTEXTCOUNT, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE } from '@
|
||||
import i18n from '@renderer/i18n'
|
||||
import store from '@renderer/store'
|
||||
import { addAssistant } from '@renderer/store/assistants'
|
||||
import { topicsActions } from '@renderer/store/topics'
|
||||
import type { Agent, Assistant, AssistantSettings, Model, Provider, Topic } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
|
||||
@ -11,7 +12,7 @@ export function getDefaultAssistant(): Assistant {
|
||||
name: i18n.t('chat.default.name'),
|
||||
emoji: '😀',
|
||||
prompt: '',
|
||||
topics: [getDefaultTopic('default')],
|
||||
topics: [],
|
||||
messages: [],
|
||||
type: 'assistant',
|
||||
regularPhrases: [] // Added regularPhrases
|
||||
@ -124,13 +125,13 @@ export async function createAssistantFromAgent(agent: Agent) {
|
||||
id: assistantId,
|
||||
name: agent.name,
|
||||
emoji: agent.emoji,
|
||||
topics: [topic],
|
||||
model: agent.defaultModel,
|
||||
type: 'assistant',
|
||||
regularPhrases: agent.regularPhrases || [] // Ensured regularPhrases
|
||||
}
|
||||
|
||||
store.dispatch(addAssistant(assistant))
|
||||
store.dispatch(topicsActions.addTopic({ assistantId, topic }))
|
||||
|
||||
window.message.success({
|
||||
content: i18n.t('message.assistant.added.content'),
|
||||
|
||||
@ -9,14 +9,9 @@ export interface AssistantsState {
|
||||
tagsOrder: string[]
|
||||
}
|
||||
|
||||
// 之前的两个实例会导致两个助手不一致的问题
|
||||
// FIXME: 更彻底的办法在这次重构就直接把二者合并了
|
||||
// Create a single default assistant instance to ensure consistency
|
||||
const defaultAssistant = getDefaultAssistant()
|
||||
|
||||
const initialState: AssistantsState = {
|
||||
defaultAssistant: defaultAssistant,
|
||||
assistants: [defaultAssistant], // Share the same reference
|
||||
defaultAssistant: getDefaultAssistant(), // 这个是模型设置的默认助手
|
||||
assistants: [getDefaultAssistant()], // 这个是主页列表的默认助手
|
||||
tagsOrder: []
|
||||
}
|
||||
|
||||
@ -27,21 +22,9 @@ const assistantsSlice = createSlice({
|
||||
updateDefaultAssistant: (state, action: PayloadAction<{ assistant: Assistant }>) => {
|
||||
const assistant = action.payload.assistant
|
||||
state.defaultAssistant = assistant
|
||||
|
||||
// Also update the corresponding assistant in the array
|
||||
const index = state.assistants.findIndex((a) => a.id === assistant.id)
|
||||
if (index !== -1) {
|
||||
state.assistants[index] = assistant
|
||||
}
|
||||
},
|
||||
updateAssistants: (state, action: PayloadAction<Assistant[]>) => {
|
||||
state.assistants = action.payload
|
||||
|
||||
// Update defaultAssistant if it exists in the new array
|
||||
const defaultInArray = action.payload.find((a) => a.id === state.defaultAssistant.id)
|
||||
if (defaultInArray) {
|
||||
state.defaultAssistant = defaultInArray
|
||||
}
|
||||
},
|
||||
addAssistant: (state, action: PayloadAction<Assistant>) => {
|
||||
state.assistants.push(action.payload)
|
||||
@ -52,11 +35,6 @@ const assistantsSlice = createSlice({
|
||||
updateAssistant: (state, action: PayloadAction<Assistant>) => {
|
||||
const assistant = action.payload
|
||||
state.assistants = state.assistants.map((c) => (c.id === assistant.id ? assistant : c))
|
||||
|
||||
// Also update defaultAssistant if it's the same assistant
|
||||
if (state.defaultAssistant.id === assistant.id) {
|
||||
state.defaultAssistant = assistant
|
||||
}
|
||||
},
|
||||
updateAssistantSettings: (
|
||||
state,
|
||||
@ -91,14 +69,6 @@ const assistantsSlice = createSlice({
|
||||
}
|
||||
: assistant
|
||||
)
|
||||
|
||||
// Also update defaultAssistant if it's the same assistant
|
||||
if (state.defaultAssistant.id === assistantId) {
|
||||
state.defaultAssistant = {
|
||||
...state.defaultAssistant,
|
||||
model: model
|
||||
}
|
||||
}
|
||||
},
|
||||
setTagsOrder: (state, action: PayloadAction<string[]>) => {
|
||||
state.tagsOrder = action.payload
|
||||
|
||||
@ -1570,26 +1570,21 @@ const migrateConfig = {
|
||||
},
|
||||
'113': (state: RootState) => {
|
||||
try {
|
||||
// Step 1: Merge defaultAssistant and assistants[0] topics to ensure consistency
|
||||
// This fixes any inconsistencies from backup restores or previous versions
|
||||
// Step 1: 把默认助手模板下面的话题合并到主页列表的默认助手Id下面,保持默认助手模板的纯粹性
|
||||
|
||||
if (state.assistants?.defaultAssistant && state.assistants?.assistants?.length > 0) {
|
||||
const defaultAssistantId = state.assistants.defaultAssistant.id
|
||||
const defaultAssistantId = state['assistants'].defaultAssistant.id
|
||||
const defaultAssistantInArray = state.assistants.assistants.find((a) => a.id === defaultAssistantId)
|
||||
|
||||
if (defaultAssistantInArray) {
|
||||
// Merge topics from both defaultAssistant and assistants[0]
|
||||
const defaultTopics = state.assistants.defaultAssistant.topics || []
|
||||
const defaultTopics = state['assistants'].defaultAssistant.topics || []
|
||||
const arrayTopics = defaultAssistantInArray.topics || []
|
||||
|
||||
// Create a map to avoid duplicates (by topic id)
|
||||
const topicsMap = new Map<string, Topic>()
|
||||
|
||||
// Add topics from both sources
|
||||
const allTopics = [...defaultTopics, ...arrayTopics]
|
||||
const allTopics = [...arrayTopics, ...defaultTopics]
|
||||
allTopics.forEach((topic) => {
|
||||
if (topic && topic.id) {
|
||||
// Keep the one with more recent updatedAt, or prefer the one from assistants array
|
||||
const existing = topicsMap.get(topic.id)
|
||||
if (
|
||||
!existing ||
|
||||
@ -1603,19 +1598,14 @@ const migrateConfig = {
|
||||
|
||||
const mergedTopics = Array.from(topicsMap.values())
|
||||
|
||||
// Update both defaultAssistant and the assistant in array
|
||||
state.assistants.defaultAssistant.topics = mergedTopics
|
||||
state['assistants'].defaultAssistant.topics = []
|
||||
defaultAssistantInArray.topics = mergedTopics
|
||||
} else {
|
||||
// defaultAssistant not found in array, add it
|
||||
state.assistants.assistants.unshift(state.assistants.defaultAssistant)
|
||||
// 如果默认助手不存在,说明被用户删掉了
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Migrate from nested topic structure to flattened topic structure
|
||||
// This should run after v112 which ensures defaultAssistant and assistants[0] consistency
|
||||
|
||||
// Initialize the new topics slice if it doesn't exist
|
||||
// Step 2: 迁移话题结构,从嵌套结构迁移到扁平结构
|
||||
if (!state.topics) {
|
||||
state.topics = {
|
||||
ids: [],
|
||||
@ -1632,8 +1622,8 @@ const migrateConfig = {
|
||||
const topicIdsByAssistant: Record<string, string[]> = {}
|
||||
|
||||
// Process regular assistants
|
||||
if (state.assistants?.assistants) {
|
||||
state.assistants.assistants.forEach((assistant) => {
|
||||
if (state['assistants'].assistants && state['assistants'].assistants.length > 0) {
|
||||
state['assistants'].assistants.forEach((assistant) => {
|
||||
const legacyAssistant = assistant as LegacyAssistant
|
||||
if (legacyAssistant.topics && Array.isArray(legacyAssistant.topics) && legacyAssistant.topics.length > 0) {
|
||||
allTopics.push(...legacyAssistant.topics)
|
||||
@ -1653,14 +1643,6 @@ const migrateConfig = {
|
||||
})
|
||||
}
|
||||
|
||||
// Process default assistant - should already be consistent after v112
|
||||
if (state.assistants?.defaultAssistant) {
|
||||
const legacyDefaultAssistant = state.assistants.defaultAssistant as LegacyAssistant
|
||||
|
||||
// Since v112 already ensured consistency, just clear the deprecated field
|
||||
legacyDefaultAssistant.topics = []
|
||||
}
|
||||
|
||||
// Populate the new topics slice
|
||||
const topicEntities: Record<string, Topic> = {}
|
||||
const topicIds: string[] = []
|
||||
@ -1670,7 +1652,6 @@ const migrateConfig = {
|
||||
topicIds.push(topic.id)
|
||||
})
|
||||
|
||||
// Update topics slice
|
||||
state.topics = {
|
||||
ids: topicIds,
|
||||
entities: topicEntities,
|
||||
@ -1679,7 +1660,6 @@ const migrateConfig = {
|
||||
|
||||
return state
|
||||
} catch (error) {
|
||||
console.error('Migration 112 failed:', error)
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,9 +130,7 @@ const topicsSlice = createSlice({
|
||||
topicsAdapter.removeMany(state, topicIds)
|
||||
|
||||
// Create default topic
|
||||
const defaultTopic = getDefaultTopic(assistantId)
|
||||
topicsAdapter.addOne(state, defaultTopic)
|
||||
state.topicIdsByAssistant[assistantId] = [defaultTopic.id]
|
||||
topicsActions.addDefaultTopic({ assistantId })
|
||||
},
|
||||
moveTopic(state, action: PayloadAction<MoveTopicPayload>) {
|
||||
const { fromAssistantId, toAssistantId, topicId } = action.payload
|
||||
@ -154,6 +152,12 @@ const topicsSlice = createSlice({
|
||||
state.topicIdsByAssistant[toAssistantId] = []
|
||||
}
|
||||
state.topicIdsByAssistant[toAssistantId].unshift(topicId)
|
||||
},
|
||||
addDefaultTopic(state, action: PayloadAction<{ assistantId: string }>) {
|
||||
const { assistantId } = action.payload
|
||||
const defaultTopic = getDefaultTopic(assistantId)
|
||||
topicsAdapter.addOne(state, defaultTopic)
|
||||
state.topicIdsByAssistant[assistantId] = [defaultTopic.id]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
Reference in New Issue
Block a user