ForcePilot/web/src/stores/agent.js

554 lines
17 KiB
JavaScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { agentApi, databaseApi, mcpApi, skillApi } from '@/apis'
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 availableKnowledgeBases = ref([])
const availableMcps = ref([])
const availableSkills = ref([])
// 智能体配置相关状态
const agentConfig = ref({})
const originalAgentConfig = ref({})
const agentConfigs = ref({})
const selectedAgentConfigId = ref(null)
// 智能体详情相关状态
const agentDetails = ref({}) // 存储每个智能体的详细信息(含 configurable_items
// 加载状态
const isLoadingAgents = ref(false)
const isLoadingConfig = ref(false)
const isLoadingAgentConfigs = 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 availableTools = computed(() => {
return configurableItems.value.tools?.options || []
})
const hasConfigChanges = computed(
() => JSON.stringify(agentConfig.value) !== JSON.stringify(originalAgentConfig.value)
)
const selectedConfigSummary = computed(() => {
const agentId = selectedAgentId.value
const configId = selectedAgentConfigId.value
if (!agentId || !configId) return null
const list = agentConfigs.value[agentId] || []
return list.find((c) => c.id === configId) || null
})
// ==================== 方法 ====================
/**
* 获取可提及的资源知识库MCPSkills
*/
async function fetchMentionResources() {
try {
const [dbsRes, mcpsRes, skillsRes] = await Promise.all([
databaseApi.getAccessibleDatabases().catch(() => ({ databases: [] })),
mcpApi.getMcpServers().catch(() => ({ data: [] })),
skillApi.listSkills().catch(() => ({ data: [] }))
])
availableKnowledgeBases.value = dbsRes.databases || []
availableMcps.value = mcpsRes.data || []
availableSkills.value = skillsRes.data || []
} catch (e) {
console.warn('Failed to fetch mention resources:', e)
}
}
/**
* 初始化 store
*/
async function initialize() {
if (isInitialized.value) return
// 防止并发初始化
if (isInitializing.value) return
isInitializing.value = true
try {
await fetchAgents()
await fetchDefaultAgent()
await fetchMentionResources()
if (!selectedAgent.value) {
if (defaultAgent.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) {
try {
await fetchAgentConfigs(selectedAgentId.value)
const list = agentConfigs.value[selectedAgentId.value] || []
const persistedId = selectedAgentConfigId.value
const persistedItem = persistedId ? list.find((c) => c.id === persistedId) : null
const defaultItem = list.find((c) => c.is_default) || list[0]
const pickId = (persistedItem || defaultItem)?.id || null
selectedAgentConfigId.value = pickId
if (pickId) {
await loadAgentConfig(selectedAgentId.value, pickId)
}
} catch (err) {
console.warn(`Failed to init agent configs for ${selectedAgentId.value}:`, err)
}
}
}
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, forceRefresh = false) {
if (!agentId) return
// 如果已经缓存了详细信息且不强制刷新,直接返回
if (!forceRefresh && agentDetails.value[agentId]) {
return agentDetails.value[agentId]
}
isLoadingAgentDetail.value = true
error.value = null
try {
const response = await agentApi.getAgentDetail(agentId)
agentDetails.value[agentId] = response
// availableTools.value[agentId] = response.available_tools || []
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 = {}
selectedAgentConfigId.value = null
// 并行获取智能体详情和配置列表
await Promise.all([
(async () => {
try {
await fetchAgentDetail(agentId)
} catch (err) {
console.warn(`Failed to fetch agent detail for ${agentId}:`, err)
}
})(),
(async () => {
try {
await fetchAgentConfigs(agentId)
const list = agentConfigs.value[agentId] || []
const defaultItem = list.find((c) => c.is_default) || list[0]
selectedAgentConfigId.value = defaultItem ? defaultItem.id : null
if (selectedAgentConfigId.value) {
await loadAgentConfig(agentId, selectedAgentConfigId.value)
}
} catch (err) {
console.warn(`Failed to fetch agent configs for ${agentId}:`, err)
}
})()
])
}
}
/**
* 加载智能体配置
*/
async function fetchAgentConfigs(agentId = null) {
const targetAgentId = agentId || selectedAgentId.value
if (!targetAgentId) return
isLoadingAgentConfigs.value = true
error.value = null
try {
const response = await agentApi.getAgentConfigs(targetAgentId)
agentConfigs.value[targetAgentId] = response.configs || []
} catch (err) {
console.error('Failed to load agent configs:', err)
handleChatError(err, 'load')
error.value = err.message
throw err
} finally {
isLoadingAgentConfigs.value = false
}
}
async function loadAgentConfig(agentId = null, configId = null) {
const targetAgentId = agentId || selectedAgentId.value
const targetConfigId = configId || selectedAgentConfigId.value
if (!targetAgentId || !targetConfigId) return
isLoadingConfig.value = true
error.value = null
try {
const response = await agentApi.getAgentConfigProfile(targetAgentId, targetConfigId)
const configJson = response.config?.config_json || {}
const contextConfig = configJson.context || configJson
const loadedConfig = { ...contextConfig }
// 确保 configurableItems 已加载
if (!agentDetails.value[targetAgentId]) {
await fetchAgentDetail(targetAgentId)
}
// 使用 configurableItems 中的默认值补全缺失的配置项
const items = configurableItems.value
Object.keys(items).forEach((key) => {
const item = items[key]
if (loadedConfig[key] === undefined || loadedConfig[key] === null) {
// 只有当默认值存在时才设置
if (item.default !== undefined) {
loadedConfig[key] = item.default
}
}
})
agentConfig.value = loadedConfig
originalAgentConfig.value = { ...loadedConfig }
} catch (err) {
console.error('Failed to load agent config profile:', err)
handleChatError(err, 'load')
error.value = err.message
throw err
} finally {
isLoadingConfig.value = false
}
}
async function selectAgentConfig(configId) {
const targetAgentId = selectedAgentId.value
if (!targetAgentId || !configId) return
selectedAgentConfigId.value = configId
await loadAgentConfig(targetAgentId, configId)
}
/**
* 保存智能体配置
* @param {Object} options - 额外参数 (e.g., { reload_graph: true })
*/
async function saveAgentConfig(options = {}) {
const targetAgentId = selectedAgentId.value
const targetConfigId = selectedAgentConfigId.value
if (!targetAgentId || !targetConfigId) return
if (!userStore.isAdmin) return
try {
await agentApi.updateAgentConfigProfile(targetAgentId, targetConfigId, {
config_json: { context: 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
}
}
async function createAgentConfigProfile({ name, setDefault = false, fromCurrent = true } = {}) {
const targetAgentId = selectedAgentId.value
if (!targetAgentId) return null
if (!userStore.isAdmin) return null
if (!name) throw new Error('配置名称不能为空')
const baseContext = fromCurrent ? { ...agentConfig.value } : {}
const response = await agentApi.createAgentConfigProfile(targetAgentId, {
name,
config_json: { context: baseContext },
set_default: setDefault
})
await fetchAgentConfigs(targetAgentId)
const created = response?.config
if (created?.id) {
await selectAgentConfig(created.id)
}
return created
}
async function deleteSelectedAgentConfigProfile() {
const targetAgentId = selectedAgentId.value
const targetConfigId = selectedAgentConfigId.value
if (!targetAgentId || !targetConfigId) return
if (!userStore.isAdmin) return
await agentApi.deleteAgentConfigProfile(targetAgentId, targetConfigId)
await fetchAgentConfigs(targetAgentId)
const list = agentConfigs.value[targetAgentId] || []
const defaultItem = list.find((c) => c.is_default) || list[0]
selectedAgentConfigId.value = defaultItem ? defaultItem.id : null
if (selectedAgentConfigId.value) {
await loadAgentConfig(targetAgentId, selectedAgentConfigId.value)
} else {
agentConfig.value = {}
originalAgentConfig.value = {}
}
}
async function setSelectedAgentConfigDefault() {
const targetAgentId = selectedAgentId.value
const targetConfigId = selectedAgentConfigId.value
if (!targetAgentId || !targetConfigId) return
if (!userStore.isAdmin) return
await agentApi.setAgentConfigDefault(targetAgentId, targetConfigId)
await fetchAgentConfigs(targetAgentId)
}
/**
* 重置智能体配置
*/
function resetAgentConfig() {
agentConfig.value = { ...originalAgentConfig.value }
}
/**
* 更新配置项
*/
function updateConfigItem(key, value) {
agentConfig.value[key] = value
}
/**
* 更新智能体配置支持批量更新
*/
function updateAgentConfig(updates) {
Object.assign(agentConfig.value, updates)
}
/**
* 清除错误状态
*/
function clearError() {
error.value = null
}
/**
* 重置 store 状态
*/
function reset() {
agents.value = []
selectedAgentId.value = null
defaultAgentId.value = null
availableKnowledgeBases.value = []
availableMcps.value = []
availableSkills.value = []
agentConfig.value = {}
originalAgentConfig.value = {}
agentConfigs.value = {}
selectedAgentConfigId.value = null
agentDetails.value = {}
isLoadingAgents.value = false
isLoadingConfig.value = false
isLoadingAgentConfigs.value = false
isLoadingAgentDetail.value = false
error.value = null
isInitialized.value = false
isInitializing.value = false
}
return {
// 状态
agents,
selectedAgentId,
defaultAgentId,
availableKnowledgeBases,
availableMcps,
availableSkills,
agentConfig,
originalAgentConfig,
agentDetails,
isLoadingAgents,
isLoadingConfig,
isLoadingAgentDetail,
isLoadingAgentConfigs,
error,
isInitialized,
// 计算属性
selectedAgent,
defaultAgent,
agentsList,
isDefaultAgent,
configurableItems,
availableTools,
hasConfigChanges,
agentConfigs,
selectedAgentConfigId,
selectedConfigSummary,
// 方法
initialize,
fetchAgents,
fetchAgentDetail,
fetchDefaultAgent,
fetchMentionResources,
setDefaultAgent,
selectAgent,
selectAgentConfig,
fetchAgentConfigs,
loadAgentConfig,
saveAgentConfig,
createAgentConfigProfile,
deleteSelectedAgentConfigProfile,
setSelectedAgentConfigDefault,
resetAgentConfig,
updateConfigItem,
updateAgentConfig,
clearError,
reset
}
},
{
// 持久化配置
persist: {
key: 'agent-store',
storage: localStorage,
pick: ['selectedAgentId', 'selectedAgentConfigId']
}
}
)