import { ref, watch, computed } from 'vue' import { defineStore } from 'pinia' import { v4 as uuidv4 } from 'uuid' import { getAgentMapIcon } from '@/layout/components/config' import { store } from '../index' import { useStorage } from '@vueuse/core' import type { IExecuteRawResponse } from '@/api' import { useConfigStore } from '@/stores/modules/config.ts' export interface Agent { Name: string Profile: string Icon: string Classification: string apiUrl?: string apiKey?: string apiModel?: string } type HslColorVector = [number, number, number] export interface IRichText { template: string data: Record< string, { text: string style?: Record color?: HslColorVector } > } export interface TaskProcess { ActionType: string AgentName: string Description: string ID: string ImportantInput: string[] } export interface IRawStepTask { Id?: string StepName?: string TaskContent?: string InputObject_List?: string[] OutputObject?: string AgentSelection?: string[] Collaboration_Brief_frontEnd: IRichText TaskProcess: TaskProcess[] } export interface IApiAgentAction { id: string type: string agent: string description: string inputs: string[] } export interface IApiStepTask { name: string content: string inputs: string[] output: string agents: string[] brief: IRichText process: IApiAgentAction[] } // 智能体评分数据类型 export interface IScoreItem { score: number reason: string } // 单个任务的评分数据结构 export interface ITaskScoreData { aspectList: string[] // 维度列表 agentScores: Record> // agent -> 维度 -> 评分 timestamp: number // 缓存时间戳 } export interface IAgentSelectModifyAddRequest { aspectList: string[] // 维度列表 agentScores: Record> // agent -> 维度 -> 评分(与后端返回格式一致) } export interface IAgentSelectModifyInitRequest { goal: string stepTask: IApiStepTask } export interface IRawPlanResponse { 'Initial Input Object'?: string[] | string 'General Goal'?: string 'Collaboration Process'?: IRawStepTask[] } const storageKey = '$agents' as const // 清除所有以 storageKey 开头的 localStorage function clearStorageByVersion() { Object.keys(localStorage) .filter((key) => key.startsWith(storageKey)) .forEach((key) => localStorage.removeItem(key)) } export const useAgentsStore = defineStore('agents', () => { const configStore = useConfigStore() const agents = useStorage(`${storageKey}-repository`, []) function setAgents(agent: Agent[]) { agents.value = agent } // 🆕 新的按任务ID存储的评分数据 const taskScoreDataMap = useStorage>( `${storageKey}-task-score-data`, {}, ) // 🆕 预加载状态追踪(用于避免重复预加载) const preloadingTaskIds = ref>(new Set()) // 🆕 获取指定任务的评分数据(按任务ID获取) function getTaskScoreData(taskId: string): IAgentSelectModifyAddRequest | null { if (!taskId) { console.warn('⚠️ getTaskScoreData: taskId 为空') return null } const taskScoreData = taskScoreDataMap.value[taskId] if (taskScoreData) { console.log(`✅ 使用任务 ${taskId} 的缓存评分数据,维度数: ${taskScoreData.aspectList.length}`) return { aspectList: taskScoreData.aspectList, agentScores: taskScoreData.agentScores, } } console.log(`ℹ️ 任务 ${taskId} 没有缓存的评分数据`) return null } // 🆕 设置指定任务的评分数据 function setTaskScoreData(taskId: string, data: IAgentSelectModifyAddRequest) { if (!taskId) { console.warn('⚠️ setTaskScoreData: taskId 为空,无法存储') return } taskScoreDataMap.value = { ...taskScoreDataMap.value, [taskId]: { ...data, timestamp: Date.now(), }, } console.log(`✅ 任务 ${taskId} 的评分数据已存储`, { aspectCount: data.aspectList.length, agentCount: Object.keys(data.agentScores).length, }) } // 🆕 检查指定任务是否有评分数据 function hasTaskScoreData(taskId: string): boolean { if (!taskId) return false return !!taskScoreDataMap.value[taskId]?.aspectList?.length } // 🆕 获取所有已预加载的任务ID列表 function getPreloadedTaskIds(): string[] { return Object.keys(taskScoreDataMap.value) } // 🆕 清除指定任务的评分数据 function clearTaskScoreData(taskId: string) { if (taskId && taskScoreDataMap.value[taskId]) { const newMap = { ...taskScoreDataMap.value } delete newMap[taskId] taskScoreDataMap.value = newMap console.log(`✅ 任务 ${taskId} 的评分数据已清除`) } } // 🆕 清除所有任务的评分数据 function clearAllTaskScoreData() { taskScoreDataMap.value = {} preloadingTaskIds.value.clear() console.log('✅ 所有任务的评分数据已清除') } // 🆕 标记任务正在预加载中 function markTaskPreloading(taskId: string) { preloadingTaskIds.value.add(taskId) } // 🆕 标记任务预加载完成 function markTaskPreloadComplete(taskId: string) { preloadingTaskIds.value.delete(taskId) } // 🆕 检查任务是否正在预加载 function isTaskPreloading(taskId: string): boolean { return preloadingTaskIds.value.has(taskId) } // 兼容旧版本:全局评分数据存储(单任务模式,已废弃,保留用于兼容) const IAgentSelectModifyAddRequest = useStorage( `${storageKey}-score-data`, null, ) // 设置智能体评分数据(兼容旧版本) function setAgentScoreData(data: IAgentSelectModifyAddRequest) { IAgentSelectModifyAddRequest.value = data } // 添加新维度的评分数据(追加模式) function addAgentScoreAspect(aspectName: string, scores: Record) { if (!IAgentSelectModifyAddRequest.value) { IAgentSelectModifyAddRequest.value = { aspectList: [], agentScores: {}, } } // 检查维度是否已存在 if (!IAgentSelectModifyAddRequest.value.aspectList.includes(aspectName)) { IAgentSelectModifyAddRequest.value.aspectList.push(aspectName) } // 添加该维度的评分数据 for (const [agentName, scoreItem] of Object.entries(scores)) { if (!IAgentSelectModifyAddRequest.value.agentScores[agentName]) { IAgentSelectModifyAddRequest.value.agentScores[agentName] = {} } IAgentSelectModifyAddRequest.value.agentScores[agentName][aspectName] = scoreItem } } // 清除智能体评分数据(兼容旧版本) function clearAgentScoreData() { IAgentSelectModifyAddRequest.value = null } // 智能体分配确认的组合列表存储 - 按任务ID分别存储(不持久化到localStorage) const confirmedAgentGroupsMap = ref>(new Map()) // 获取指定任务的确认的agent组合列表 function getConfirmedAgentGroups(taskId: string): string[][] { return confirmedAgentGroupsMap.value.get(taskId) || [] } // 添加确认的agent组合到指定任务 function addConfirmedAgentGroup(taskId: string, group: string[]) { const groups = confirmedAgentGroupsMap.value.get(taskId) || [] groups.push(group) confirmedAgentGroupsMap.value.set(taskId, groups) } // 清除指定任务的确认的agent组合列表 function clearConfirmedAgentGroups(taskId: string) { confirmedAgentGroupsMap.value.delete(taskId) } // 清除所有任务的确认的agent组合列表 function clearAllConfirmedAgentGroups() { confirmedAgentGroupsMap.value.clear() } const planModificationWindow = ref(false) const planTaskWindow = ref(false) const agentAllocationDialog = ref(false) function openPlanModification() { planModificationWindow.value = true } function closePlanModification() { planModificationWindow.value = false } function openPlanTask() { planTaskWindow.value = true } function closePlanTask() { planTaskWindow.value = false } function openAgentAllocationDialog() { agentAllocationDialog.value = true } function closeAgentAllocationDialog() { agentAllocationDialog.value = false } // 任务搜索的内容 const searchValue = useStorage(`${storageKey}-search-value`, '') function setSearchValue(value: string) { searchValue.value = value } const storageVersionIdentifier = useStorage( `${storageKey}-storage-version-identifier`, '', ) // 监听 configStore.config.agentRepository.storageVersionIdentifier 改变 watch( () => configStore.config.agentRepository.storageVersionIdentifier, (value) => { // value与storageVersionIdentifier不一致清除所有storageKey开头的localStorage if (value !== storageVersionIdentifier.value) { clearStorageByVersion() storageVersionIdentifier.value = value } }, { immediate: true, }, ) // 当前的展示的任务流程 const currentTask = ref() // 记录用户修改过的步骤索引(用于重新执行) const modifiedSteps = ref>(new Set()) function addModifiedStep(stepIndex: number) { modifiedSteps.value.add(stepIndex) } function clearModifiedSteps() { modifiedSteps.value.clear() } function hasModifiedSteps() { return modifiedSteps.value.size > 0 } function setCurrentTask(task: IRawStepTask) { const existingTask = currentTask.value // 🆕 智能判断:如果是同一个任务,保留用户修改过的数据(AgentSelection、TaskProcess、Collaboration_Brief_frontEnd) if (existingTask && existingTask.Id === task.Id) { currentTask.value = { ...task, AgentSelection: existingTask.AgentSelection || task.AgentSelection, TaskProcess: existingTask.TaskProcess || task.TaskProcess, Collaboration_Brief_frontEnd: existingTask.Collaboration_Brief_frontEnd || task.Collaboration_Brief_frontEnd, } // 🆕 同步更新主流程数据(让执行结果卡片和任务大纲都能联动) syncCurrentTaskToMainProcess(currentTask.value) console.log('🔄 setCurrentTask: 保留同一任务的分支数据', { taskId: task.Id, taskName: task.StepName, preservedAgentSelection: currentTask.value.AgentSelection, preservedTaskProcessLength: currentTask.value.TaskProcess?.length || 0, }) } else { // 不同任务:使用新任务数据 currentTask.value = task console.log('🔄 setCurrentTask: 切换到不同任务', { taskId: task.Id, taskName: task.StepName, agentSelection: task.AgentSelection, taskProcessLength: task.TaskProcess?.length || 0, }) } } // 🆕 同步 currentTask 到主流程数据 function syncCurrentTaskToMainProcess(updatedTask: IRawStepTask) { const collaborationProcess = agentRawPlan.value.data?.['Collaboration Process'] if (!collaborationProcess) { console.warn('⚠️ syncCurrentTaskToMainProcess: collaborationProcess 不存在') return } const taskIndex = collaborationProcess.findIndex((t) => t.Id === updatedTask.Id) if (taskIndex === -1) { console.warn('⚠️ syncCurrentTaskToMainProcess: 未找到对应任务', updatedTask.Id) return } // 使用 splice 确保 Vue 响应式更新 collaborationProcess.splice(taskIndex, 1, { ...collaborationProcess[taskIndex]!, AgentSelection: updatedTask.AgentSelection || [], TaskProcess: updatedTask.TaskProcess || [], Collaboration_Brief_frontEnd: updatedTask.Collaboration_Brief_frontEnd, }) console.log('✅ syncCurrentTaskToMainProcess: 已同步到主流程', { taskName: collaborationProcess[taskIndex]!.StepName, agentSelection: collaborationProcess[taskIndex]!.AgentSelection, taskProcessLength: collaborationProcess[taskIndex]!.TaskProcess?.length || 0, }) } // 🆕 设置当前任务的 TaskProcess 数据(用于切换分支时更新显示) function setCurrentTaskProcess(taskProcess: TaskProcess[]) { if (currentTask.value) { // 创建新的对象引用,确保响应式更新 currentTask.value = { ...currentTask.value, TaskProcess: JSON.parse(JSON.stringify(taskProcess)), } // 🆕 同步到主流程数据(让执行结果卡片和任务大纲都能联动) syncCurrentTaskToMainProcess(currentTask.value) console.log('✅ 已更新 currentTask.TaskProcess 并同步到主流程:', { taskId: currentTask.value.Id, agent数量: taskProcess.length, }) } } // 🆕 更新当前任务的 AgentSelection 和 TaskProcess(用于在 AgentAllocation 中切换 agent 组合) // 此函数专门用于强制更新,不会被 setCurrentTask 的"智能保留"逻辑阻止 function updateCurrentAgentSelection( agentSelection: string[], taskProcess: TaskProcess[], collaborationBrief: any, ) { if (currentTask.value) { // 直接更新 currentTask,不保留旧数据 currentTask.value = { ...currentTask.value, AgentSelection: agentSelection, TaskProcess: taskProcess, Collaboration_Brief_frontEnd: collaborationBrief, } // 同步到主流程数据 syncCurrentTaskToMainProcess(currentTask.value) console.log('✅ 已强制更新 currentTask 的 AgentSelection 并同步到主流程:', { taskId: currentTask.value.Id, taskName: currentTask.value.StepName, newAgentSelection: agentSelection, taskProcessLength: taskProcess.length, }) } } const agentRawPlan = ref<{ data?: IRawPlanResponse; loading?: boolean }>({ loading: false }) function setAgentRawPlan(plan: { data?: IRawPlanResponse; loading?: boolean }) { if (plan.data) { plan.data['Collaboration Process'] = plan.data['Collaboration Process']?.map((item) => ({ ...item, // ✅ 只在任务没有 Id 时才生成新的 ID,保持已存在任务的 Id 不变 Id: item.Id || uuidv4(), })) } agentRawPlan.value = { ...agentRawPlan.value, ...plan, } } // 执行完任务的结果 const executePlan = ref([]) function setExecutePlan(plan: IExecuteRawResponse[]) { executePlan.value = plan } function resetAgent() { agentRawPlan.value = { loading: false, } currentTask.value = undefined executePlan.value = [] hasStoppedFilling.value = false } // 额外的产物列表 const additionalOutputs = ref([]) // 用户在 Assignment 中选择的 agent 组合(按任务ID分别存储) const selectedAgentGroupMap = ref>(new Map()) // 设置指定任务的选择的 agent 组合 function setSelectedAgentGroup(taskId: string, agents: string[]) { selectedAgentGroupMap.value.set(taskId, agents) console.log('💾 保存任务选择的 agent 组合:', { taskId, agents }) } // 获取指定任务的选择的 agent 组合 function getSelectedAgentGroup(taskId: string): string[] | undefined { return selectedAgentGroupMap.value.get(taskId) } // 清除指定任务的选择的 agent 组合 function clearSelectedAgentGroup(taskId: string) { selectedAgentGroupMap.value.delete(taskId) } // 清除所有任务的选择的 agent 组合 function clearAllSelectedAgentGroups() { selectedAgentGroupMap.value.clear() } // 添加新产物 function addNewOutput(outputObject: string) { if (!outputObject.trim()) return false const trimmedOutput = outputObject.trim() if (!additionalOutputs.value.includes(trimmedOutput)) { additionalOutputs.value.unshift(trimmedOutput) return true } return false } // 删除额外产物 function removeAdditionalOutput(outputObject: string) { const index = additionalOutputs.value.indexOf(outputObject) if (index > -1) { additionalOutputs.value.splice(index, 1) return true } return false } // 清除额外产物 function clearAdditionalOutputs() { additionalOutputs.value = [] } // 标记是否用户已停止智能体分配过程 const hasStoppedFilling = ref(false) // 设置停止状态 function setHasStoppedFilling(value: boolean) { hasStoppedFilling.value = value } return { agents, setAgents, searchValue, setSearchValue, currentTask, setCurrentTask, setCurrentTaskProcess, // 🆕 设置当前任务的 TaskProcess updateCurrentAgentSelection, // 🆕 强制更新 AgentSelection(用于 AgentAllocation 切换组合) syncCurrentTaskToMainProcess, // 🆕 同步 currentTask 到主流程 agentRawPlan, setAgentRawPlan, executePlan, setExecutePlan, resetAgent, additionalOutputs, addNewOutput, removeAdditionalOutput, clearAdditionalOutputs, // 用户选择的 agent 组合 selectedAgentGroupMap, setSelectedAgentGroup, getSelectedAgentGroup, clearSelectedAgentGroup, clearAllSelectedAgentGroups, planModificationWindow, openPlanModification, closePlanModification, planTaskWindow, openPlanTask, closePlanTask, agentAllocationDialog, openAgentAllocationDialog, closeAgentAllocationDialog, // 智能体评分数据 IAgentSelectModifyAddRequest, setAgentScoreData, addAgentScoreAspect, clearAgentScoreData, // 🆕 按任务ID存储的评分数据 taskScoreDataMap, getTaskScoreData, setTaskScoreData, hasTaskScoreData, getPreloadedTaskIds, clearTaskScoreData, clearAllTaskScoreData, preloadingTaskIds, markTaskPreloading, markTaskPreloadComplete, isTaskPreloading, // 确认的agent组合列表(按任务ID分别存储) confirmedAgentGroupsMap, getConfirmedAgentGroups, addConfirmedAgentGroup, clearConfirmedAgentGroups, clearAllConfirmedAgentGroups, // 停止填充状态 hasStoppedFilling, setHasStoppedFilling, // 重新执行相关 modifiedSteps, addModifiedStep, clearModifiedSteps, hasModifiedSteps, } }) /** * 用于在组件外部(如在Pinia Store 中)使用 Pinia 提供的 store 实例。 * 官方文档解释了如何在组件外部使用 Pinia Store: * https://pinia.vuejs.org/core-concepts/outside-component-usage.html#using-a-store-outside-of-a-component */ export function useAgentsStoreHook() { return useAgentsStore(store) }