612 lines
18 KiB
TypeScript
612 lines
18 KiB
TypeScript
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<string, string>
|
||
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<string, Record<string, IScoreItem>> // agent -> 维度 -> 评分
|
||
timestamp: number // 缓存时间戳
|
||
}
|
||
|
||
export interface IAgentSelectModifyAddRequest {
|
||
aspectList: string[] // 维度列表
|
||
agentScores: Record<string, Record<string, IScoreItem>> // 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<Agent[]>(`${storageKey}-repository`, [])
|
||
function setAgents(agent: Agent[]) {
|
||
agents.value = agent
|
||
}
|
||
|
||
// 🆕 新的按任务ID存储的评分数据
|
||
const taskScoreDataMap = useStorage<Record<string, ITaskScoreData>>(
|
||
`${storageKey}-task-score-data`,
|
||
{},
|
||
)
|
||
|
||
// 🆕 预加载状态追踪(用于避免重复预加载)
|
||
const preloadingTaskIds = ref<Set<string>>(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<IAgentSelectModifyAddRequest | null>(
|
||
`${storageKey}-score-data`,
|
||
null,
|
||
)
|
||
|
||
// 设置智能体评分数据(兼容旧版本)
|
||
function setAgentScoreData(data: IAgentSelectModifyAddRequest) {
|
||
IAgentSelectModifyAddRequest.value = data
|
||
}
|
||
|
||
// 添加新维度的评分数据(追加模式)
|
||
function addAgentScoreAspect(aspectName: string, scores: Record<string, IScoreItem>) {
|
||
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<Map<string, string[][]>>(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<string>(`${storageKey}-search-value`, '')
|
||
function setSearchValue(value: string) {
|
||
searchValue.value = value
|
||
}
|
||
|
||
const storageVersionIdentifier = useStorage<string>(
|
||
`${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<IRawStepTask>()
|
||
|
||
// 记录用户修改过的步骤索引(用于重新执行)
|
||
const modifiedSteps = ref<Set<number>>(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<IExecuteRawResponse[]>([])
|
||
function setExecutePlan(plan: IExecuteRawResponse[]) {
|
||
executePlan.value = plan
|
||
}
|
||
|
||
function resetAgent() {
|
||
agentRawPlan.value = {
|
||
loading: false,
|
||
}
|
||
currentTask.value = undefined
|
||
executePlan.value = []
|
||
hasStoppedFilling.value = false
|
||
}
|
||
|
||
// 额外的产物列表
|
||
const additionalOutputs = ref<string[]>([])
|
||
|
||
// 用户在 Assignment 中选择的 agent 组合(按任务ID分别存储)
|
||
const selectedAgentGroupMap = ref<Map<string, string[]>>(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)
|
||
}
|