ForcePilot/web/src/stores/agent.js

382 lines
9.6 KiB
JavaScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { agentApi } from '@/apis/agent_api'
import { handleChatError } from '@/utils/errorHandler'
import { useUserStore } from '@/stores/user'
export const useAgentStore = defineStore('agent', () => {
const userStore = useUserStore()
// ==================== 状态定义 ====================
// 智能体相关状态
const agents = ref([])
const selectedAgentId = ref(null)
const defaultAgentId = ref(null)
// 智能体配置相关状态
const agentConfig = ref({})
const originalAgentConfig = ref({})
// 智能体详情相关状态
const agentDetails = ref({}) // 存储每个智能体的详细信息(含 configurable_items
// 工具相关状态
const availableTools = ref([])
// 加载状态
const isLoadingAgents = ref(false)
const isLoadingConfig = ref(false)
const isLoadingTools = ref(false)
const isLoadingAgentDetail = ref(false)
// 错误状态
const error = ref(null)
// 初始化状态
const isInitialized = ref(false)
const isInitializing = ref(false)
// ==================== 计算属性 ====================
const selectedAgent = computed(() =>
selectedAgentId.value ? agents.value.find(a => a.id === selectedAgentId.value) : null
)
const defaultAgent = computed(() =>
defaultAgentId.value ? agents.value.find(a => a.id === defaultAgentId.value) : agents.value[0]
)
const agentsList = computed(() => agents.value)
const isDefaultAgent = computed(() => selectedAgentId.value === defaultAgentId.value)
const configurableItems = computed(() => {
const agentId = selectedAgentId.value
if (!agentId || !agentDetails.value[agentId] || !agentDetails.value[agentId].configurable_items) {
return {}
}
const agentConfigurableItems = agentDetails.value[agentId].configurable_items
const items = { ...agentConfigurableItems }
Object.keys(items).forEach(key => {
const item = items[key]
if (item && item.x_oap_ui_config) {
items[key] = { ...item, ...item.x_oap_ui_config }
delete items[key].x_oap_ui_config
}
})
return items
})
const hasConfigChanges = computed(() =>
JSON.stringify(agentConfig.value) !== JSON.stringify(originalAgentConfig.value)
)
// ==================== 方法 ====================
/**
* 初始化 store
*/
async function initialize() {
if (isInitialized.value) return
// 防止并发初始化
if (isInitializing.value) return
isInitializing.value = true
try {
await fetchAgents()
await fetchDefaultAgent()
if (!selectedAgentId.value || !agents.value.find(a => a.id === selectedAgentId.value)) {
if (defaultAgentId.value && agents.value.find(a => a.id === defaultAgentId.value)) {
await selectAgent(defaultAgentId.value)
} else if (agents.value.length > 0) {
const firstAgentId = agents.value[0].id
await selectAgent(firstAgentId)
}
} else {
console.log('Condition FALSE: Persisted selected agent is valid. Keeping it.')
// 确保已缓存的智能体详细信息存在
if (selectedAgentId.value && !agentDetails.value[selectedAgentId.value]) {
try {
await fetchAgentDetail(selectedAgentId.value)
} catch (err) {
console.warn(`Failed to fetch agent detail for ${selectedAgentId.value}:`, err)
}
}
}
if (selectedAgentId.value) {
if (userStore.isAdmin) {
await loadAgentConfig()
}
await fetchTools()
}
isInitialized.value = true
} catch (err) {
console.error('Failed to initialize agent store:', err)
handleChatError(err, 'initialize')
error.value = err.message
} finally {
isInitializing.value = false
}
}
/**
* 获取智能体列表
*/
async function fetchAgents() {
isLoadingAgents.value = true
error.value = null
try {
const response = await agentApi.getAgents()
agents.value = response.agents
} catch (err) {
console.error('Failed to fetch agents:', err)
handleChatError(err, 'fetch')
error.value = err.message
throw err
} finally {
isLoadingAgents.value = false
}
}
/**
* 获取单个智能体的详细信息包含配置选项
* @param {string} agentId - 智能体ID
*/
async function fetchAgentDetail(agentId) {
if (!agentId) return
// 如果已经缓存了详细信息,直接返回
if (agentDetails.value[agentId]) {
return agentDetails.value[agentId]
}
isLoadingAgentDetail.value = true
error.value = null
try {
const response = await agentApi.getAgentDetail(agentId)
agentDetails.value[agentId] = response
return response
} catch (err) {
console.error(`Failed to fetch agent detail for ${agentId}:`, err)
handleChatError(err, 'fetch')
error.value = err.message
throw err
} finally {
isLoadingAgentDetail.value = false
}
}
/**
* 获取默认智能体
*/
async function fetchDefaultAgent() {
try {
const response = await agentApi.getDefaultAgent()
defaultAgentId.value = response.default_agent_id
} catch (err) {
console.error('Failed to fetch default agent:', err)
handleChatError(err, 'fetch')
error.value = err.message
}
}
/**
* 设置默认智能体
*/
async function setDefaultAgent(agentId) {
try {
await agentApi.setDefaultAgent(agentId)
defaultAgentId.value = agentId
} catch (err) {
console.error('Failed to set default agent:', err)
handleChatError(err, 'save')
error.value = err.message
throw err
}
}
/**
* 选择智能体
*/
async function selectAgent(agentId) {
if (agents.value.find(a => a.id === agentId)) {
selectedAgentId.value = agentId
// 清空之前的配置
agentConfig.value = {}
originalAgentConfig.value = {}
// 自动获取智能体详细信息(包含 configurable_items
try {
await fetchAgentDetail(agentId)
} catch (err) {
console.warn(`Failed to fetch agent detail for ${agentId}:`, err)
// 不抛出错误,允许继续选择智能体
}
}
}
/**
* 加载智能体配置
*/
async function loadAgentConfig(agentId = null) {
if (!userStore.isAdmin) return
const targetAgentId = agentId || selectedAgentId.value
if (!targetAgentId) return
isLoadingConfig.value = true
error.value = null
try {
const response = await agentApi.getAgentConfig(targetAgentId)
agentConfig.value = { ...response.config }
originalAgentConfig.value = { ...response.config }
} catch (err) {
console.error('Failed to load agent config:', err)
handleChatError(err, 'load')
error.value = err.message
throw err
} finally {
isLoadingConfig.value = false
}
}
/**
* 保存智能体配置
*/
async function saveAgentConfig(agentId = null) {
const targetAgentId = agentId || selectedAgentId.value
if (!targetAgentId) return
try {
await agentApi.saveAgentConfig(targetAgentId, agentConfig.value)
originalAgentConfig.value = { ...agentConfig.value }
} catch (err) {
console.error('Failed to save agent config:', err)
handleChatError(err, 'save')
error.value = err.message
throw err
}
}
/**
* 重置智能体配置
*/
function resetAgentConfig() {
agentConfig.value = { ...originalAgentConfig.value }
}
/**
* 更新配置项
*/
function updateConfigItem(key, value) {
agentConfig.value[key] = value
}
/**
* 更新智能体配置支持批量更新
*/
function updateAgentConfig(updates) {
Object.assign(agentConfig.value, updates)
}
/**
* 获取工具列表
*/
async function fetchTools() {
isLoadingTools.value = true
error.value = null
try {
const response = await agentApi.getTools(selectedAgentId.value)
availableTools.value = response.tools
} catch (err) {
console.error('Failed to fetch tools:', err)
handleChatError(err, 'fetch')
error.value = err.message
throw err
} finally {
isLoadingTools.value = false
}
}
/**
* 清除错误状态
*/
function clearError() {
error.value = null
}
/**
* 重置 store 状态
*/
function reset() {
agents.value = []
selectedAgentId.value = null
defaultAgentId.value = null
agentConfig.value = {}
originalAgentConfig.value = {}
agentDetails.value = {}
availableTools.value = []
isLoadingAgents.value = false
isLoadingConfig.value = false
isLoadingTools.value = false
isLoadingAgentDetail.value = false
error.value = null
isInitialized.value = false
isInitializing.value = false
}
return {
// 状态
agents,
selectedAgentId,
defaultAgentId,
agentConfig,
originalAgentConfig,
agentDetails,
availableTools,
isLoadingAgents,
isLoadingConfig,
isLoadingTools,
isLoadingAgentDetail,
error,
isInitialized,
// 计算属性
selectedAgent,
defaultAgent,
agentsList,
isDefaultAgent,
configurableItems,
hasConfigChanges,
// 方法
initialize,
fetchAgents,
fetchAgentDetail,
fetchDefaultAgent,
setDefaultAgent,
selectAgent,
loadAgentConfig,
saveAgentConfig,
resetAgentConfig,
updateConfigItem,
updateAgentConfig,
fetchTools,
clearError,
reset
}
}, {
// 持久化配置
persist: {
key: 'agent-store',
storage: localStorage,
paths: ['selectedAgentId', 'defaultAgentId']
}
})