feat: 重构智能体元数据系统,从集中式 YAML 迁移到分布式 TOML 配置
This commit is contained in:
parent
bf3e8cdedf
commit
99aae1c00a
@ -6,6 +6,20 @@
|
|||||||
|
|
||||||
仓库预置了若干可直接运行的智能体:`chatbot` 聚焦对话与动态工具调度,`mini_agent` 提供精简模板,`reporter` 演示报告类链路。这些目录展示了上下文类、Graph 构造方式、子智能体引用以及中间件组合的范例,新增功能时可以直接复用。
|
仓库预置了若干可直接运行的智能体:`chatbot` 聚焦对话与动态工具调度,`mini_agent` 提供精简模板,`reporter` 演示报告类链路。这些目录展示了上下文类、Graph 构造方式、子智能体引用以及中间件组合的范例,新增功能时可以直接复用。
|
||||||
|
|
||||||
|
### 智能体元数据配置
|
||||||
|
|
||||||
|
每个智能体可以通过在智能体目录下创建 `metadata.toml` 文件来配置元数据信息。这个文件使用 TOML 格式,包含以下字段:
|
||||||
|
|
||||||
|
- `name`: 智能体显示名称
|
||||||
|
- `description`: 智能体功能描述
|
||||||
|
- `examples`: 示例问题列表(数组格式)
|
||||||
|
|
||||||
|
例如,`src/agents/chatbot/metadata.toml`:
|
||||||
|
|
||||||
|
<<< @/../src/agents/chatbot/metadata.toml
|
||||||
|
|
||||||
|
**注意**:`metadata.toml` 文件是可选的,如果没有提供,系统将使用智能体类的基本属性。
|
||||||
|
|
||||||
### 创建新的智能体
|
### 创建新的智能体
|
||||||
|
|
||||||
在 `src/agents` 下新建一个包,保持与现有目录一致的结构:放置 Graph 构造逻辑(通常命名为 `graph.py`),并在包内的 `__init__.py` 中暴露主类。
|
在 `src/agents` 下新建一个包,保持与现有目录一致的结构:放置 Graph 构造逻辑(通常命名为 `graph.py`),并在包内的 `__init__.py` 中暴露主类。
|
||||||
|
|||||||
@ -2,46 +2,48 @@
|
|||||||
|
|
||||||
路线图可能会经常变更,如果有强烈的建议,可以在 [issue](https://github.com/xerrors/Yuxi-Know/issues) 中提。
|
路线图可能会经常变更,如果有强烈的建议,可以在 [issue](https://github.com/xerrors/Yuxi-Know/issues) 中提。
|
||||||
|
|
||||||
- **[2025/10/13]** v0.3 进入 beta 测试环节,不会再封装新的特性,仅作 bug 层面的修复
|
|
||||||
|
## v0.4
|
||||||
|
|
||||||
|
|
||||||
## Bugs
|
|
||||||
|
|
||||||
- [ ] 无法展示图谱
|
### 看板
|
||||||
|
|
||||||
## Next
|
- 新建 DeepAgents 智能体(暂时没有场景)
|
||||||
|
- 添加对于上传文件的支持
|
||||||
|
- 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) [#273](https://github.com/xerrors/Yuxi-Know/issues/273) <Badge type="info" text="0.4" />
|
||||||
|
- 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示
|
||||||
|
- 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" />
|
||||||
|
- 集成 LangFuse (观望) 添加用户日志与用户反馈模块,可以在 AgentView 中查看信息
|
||||||
|
|
||||||
- [ ] 新建 DeepAgents 智能体
|
### Bugs
|
||||||
- [ ] 添加对于上传文件的支持
|
- 部分异常状态下,智能体的模型名称出现重叠[#279](https://github.com/xerrors/Yuxi-Know/issues/279)
|
||||||
- [ ] 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) <Badge type="info" text="0.4" />
|
|
||||||
- [ ] 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示
|
### 新增
|
||||||
- [ ] 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" />
|
- 优化知识库详情页面,更加简洁清晰
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- 修复重排序模型实际未生效的问题
|
||||||
|
|
||||||
|
|
||||||
## Later
|
## v0.3
|
||||||
|
### Added
|
||||||
|
- 添加测试脚本,覆盖最常见的功能(已覆盖API)
|
||||||
|
- 新建 tasker 模块,用来管理所有的后台任务,UI 上使用侧边栏管理。Tasker 中获取历史任务的时候,仅获取 top100 个 task。
|
||||||
|
- 优化对文档信息的检索展示(检索结果页、详情页)
|
||||||
|
- 优化全局配置的管理模型,优化配置管理
|
||||||
|
- 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
|
||||||
|
- 修改现有的智能体Demo,并尽量将默认助手的特性兼容到 LangGraph 的 [`create_agent`](https://docs.langchain.com/oss/python/langchain/agents) 中
|
||||||
|
- 基于 create_agent 创建 SQL Viewer 智能体 <Badge type="info" text="0.3.5" />
|
||||||
|
- 优化 MCP 逻辑,支持 common + special 创建方式 <Badge type="info" text="0.3.5" />
|
||||||
|
- LightRAG 知识库应该可以支持修改 LLM
|
||||||
|
|
||||||
下面的功能**可能**会放在后续版本实现,暂时未定
|
### Fixed
|
||||||
|
- 修复本地知识库的 metadata 和 向量数据库中不一致的情况。
|
||||||
- [ ] 集成 LangFuse (观望) 添加用户日志与用户反馈模块,可以在 AgentView 中查看信息
|
- v1 版本的 LangGraph 的工具渲染有问题
|
||||||
|
- upload 接口会阻塞主进程
|
||||||
## Done
|
- LightRAG 知识库查看不了解析后的文本,偶然出现,未复现
|
||||||
|
- 智能体的加载状态有问题:(1)智能体加载没有动画;(2)切换对话和加载中,使用同一个loading状态。
|
||||||
|
- 前端工具调用渲染出现问题
|
||||||
- [x] 添加测试脚本,覆盖最常见的功能(已覆盖API)
|
- 当前 ReAct 智能体有消息顺序错乱的 bug,且不会默认调用工具
|
||||||
- [x] 新建 tasker 模块,用来管理所有的后台任务,UI 上使用侧边栏管理。
|
- 修复文件管理:(1)文件选择的时候会跨数据库;(2)文件校验会算上失败的文件;
|
||||||
- [x] 优化对文档信息的检索展示(检索结果页、详情页)
|
|
||||||
- [x] 当前 ReAct 智能体有消息顺序错乱的 bug,且不会默认调用工具
|
|
||||||
- [x] 优化全局配置的管理模型,优化配置管理
|
|
||||||
- [x] 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
|
|
||||||
- [x] 文件管理:(1)文件选择的时候会跨数据库;(2)文件校验会算上失败的文件;
|
|
||||||
- [x] Tasker 中获取历史任务的时候,仅获取 top100 个 task。
|
|
||||||
- [x] 修改现有的智能体Demo,并尽量将默认助手的特性兼容到 LangGraph 的 [`create_agent`](https://docs.langchain.com/oss/python/langchain/agents) 中
|
|
||||||
- [x] 基于 create_agent 创建 SQL Viewer 智能体 <Badge type="info" text="0.3.5" />
|
|
||||||
- [x] 优化 MCP 逻辑,支持 common + special 创建方式 <Badge type="info" text="0.3.5" />
|
|
||||||
- [x] 修复本地知识库的 metadata 和 向量数据库中不一致的情况。
|
|
||||||
- [x] v1 版本的 LangGraph 的工具渲染有问题
|
|
||||||
- [x] upload 接口会阻塞主进程
|
|
||||||
- [x] LightRAG 知识库查看不了解析后的文本,偶然出现,未复现
|
|
||||||
- [x] LightRAG 知识库应该可以支持修改 LLM
|
|
||||||
- [x] 智能体的加载状态有问题:(1)智能体加载没有动画;(2)切换对话和加载中,使用同一个loading状态。
|
|
||||||
- [x] 前端工具调用渲染出现问题
|
|
||||||
@ -2,7 +2,6 @@ import asyncio
|
|||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
import yaml
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from fastapi import APIRouter, Body, Depends, HTTPException
|
from fastapi import APIRouter, Body, Depends, HTTPException
|
||||||
@ -304,13 +303,22 @@ async def call(query: str = Body(...), meta: dict = Body(None), current_user: Us
|
|||||||
@chat.get("/agent")
|
@chat.get("/agent")
|
||||||
async def get_agent(current_user: User = Depends(get_required_user)):
|
async def get_agent(current_user: User = Depends(get_required_user)):
|
||||||
"""获取所有可用智能体(需要登录)"""
|
"""获取所有可用智能体(需要登录)"""
|
||||||
agents = await agent_manager.get_agents_info()
|
agents_info = await agent_manager.get_agents_info()
|
||||||
# logger.debug(f"agents: {agents}")
|
|
||||||
metadata = {}
|
# Return agents with complete information
|
||||||
if Path("src/config/static/agents_meta.yaml").exists():
|
agents = [
|
||||||
with open("src/config/static/agents_meta.yaml") as f:
|
{
|
||||||
metadata = yaml.safe_load(f)
|
"id": agent_info["id"],
|
||||||
return {"agents": agents, "metadata": metadata}
|
"name": agent_info.get("name", "Unknown"),
|
||||||
|
"description": agent_info.get("description", ""),
|
||||||
|
"examples": agent_info.get("examples", []),
|
||||||
|
"configurable_items": agent_info.get("configurable_items", []),
|
||||||
|
"has_checkpointer": agent_info.get("has_checkpointer", False)
|
||||||
|
}
|
||||||
|
for agent_info in agents_info
|
||||||
|
]
|
||||||
|
|
||||||
|
return {"agents": agents}
|
||||||
|
|
||||||
|
|
||||||
# TODO:[未完成]这个thread_id在前端是直接生成的1234,最好传入thread_id时做校验只允许uuid4
|
# TODO:[未完成]这个thread_id在前端是直接生成的1234,最好传入thread_id时做校验只允许uuid4
|
||||||
|
|||||||
9
src/agents/chatbot/metadata.toml
Normal file
9
src/agents/chatbot/metadata.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name = "智能聊天助手"
|
||||||
|
description = "基础的AI对话助手,支持工具调用,MCP,并具备丰富的知识库。"
|
||||||
|
examples = [
|
||||||
|
"你好,请介绍一下你自己",
|
||||||
|
"帮我写一封商务邮件",
|
||||||
|
"解释一下什么是机器学习",
|
||||||
|
"推荐几本好书",
|
||||||
|
"如何提高工作效率?"
|
||||||
|
]
|
||||||
@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import importlib.util
|
||||||
import os
|
import os
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -8,6 +9,8 @@ from langgraph.checkpoint.memory import InMemorySaver
|
|||||||
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver, aiosqlite
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver, aiosqlite
|
||||||
from langgraph.graph.state import CompiledStateGraph
|
from langgraph.graph.state import CompiledStateGraph
|
||||||
|
|
||||||
|
import tomllib as tomli
|
||||||
|
|
||||||
from src import config as sys_config
|
from src import config as sys_config
|
||||||
from src.agents.common.context import BaseContext
|
from src.agents.common.context import BaseContext
|
||||||
from src.utils import logger
|
from src.utils import logger
|
||||||
@ -27,6 +30,7 @@ class BaseAgent:
|
|||||||
self.context_schema = BaseContext
|
self.context_schema = BaseContext
|
||||||
self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name
|
self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name
|
||||||
self.workdir.mkdir(parents=True, exist_ok=True)
|
self.workdir.mkdir(parents=True, exist_ok=True)
|
||||||
|
self._metadata_cache = None # Cache for metadata to avoid repeated file reads
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def module_name(self) -> str:
|
def module_name(self) -> str:
|
||||||
@ -39,10 +43,15 @@ class BaseAgent:
|
|||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
async def get_info(self):
|
async def get_info(self):
|
||||||
|
# Load metadata from file
|
||||||
|
metadata = self.load_metadata()
|
||||||
|
|
||||||
|
# Merge metadata with class attributes, metadata takes precedence
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"name": self.name if hasattr(self, "name") else "Unknown",
|
"name": metadata.get("name", getattr(self, "name", "Unknown")),
|
||||||
"description": self.description if hasattr(self, "description") else "Unknown",
|
"description": metadata.get("description", getattr(self, "description", "Unknown")),
|
||||||
|
"examples": metadata.get("examples", []),
|
||||||
"configurable_items": self.context_schema.get_configurable_items(),
|
"configurable_items": self.context_schema.get_configurable_items(),
|
||||||
"has_checkpointer": await self.check_checkpointer(),
|
"has_checkpointer": await self.check_checkpointer(),
|
||||||
}
|
}
|
||||||
@ -138,3 +147,43 @@ class BaseAgent:
|
|||||||
async def get_aio_memory(self) -> AsyncSqliteSaver:
|
async def get_aio_memory(self) -> AsyncSqliteSaver:
|
||||||
"""获取异步存储实例"""
|
"""获取异步存储实例"""
|
||||||
return AsyncSqliteSaver(await self.get_async_conn())
|
return AsyncSqliteSaver(await self.get_async_conn())
|
||||||
|
|
||||||
|
|
||||||
|
def load_metadata(self) -> dict:
|
||||||
|
"""Load metadata from metadata.toml file in the agent's source directory."""
|
||||||
|
if self._metadata_cache is not None:
|
||||||
|
return self._metadata_cache
|
||||||
|
|
||||||
|
# Try to find metadata.toml in the agent's source directory
|
||||||
|
try:
|
||||||
|
# Get the agent's source file directory
|
||||||
|
agent_module = self.__class__.__module__
|
||||||
|
|
||||||
|
# Use importlib to get the module's file path
|
||||||
|
spec = importlib.util.find_spec(agent_module)
|
||||||
|
if spec and spec.origin:
|
||||||
|
agent_file = Path(spec.origin)
|
||||||
|
agent_dir = agent_file.parent
|
||||||
|
else:
|
||||||
|
# Fallback: construct path from module name
|
||||||
|
module_path = agent_module.replace(".", "/")
|
||||||
|
agent_file = Path(f"src/{module_path}.py")
|
||||||
|
agent_dir = agent_file.parent
|
||||||
|
|
||||||
|
metadata_file = agent_dir / "metadata.toml"
|
||||||
|
|
||||||
|
if metadata_file.exists():
|
||||||
|
with open(metadata_file, "rb") as f:
|
||||||
|
metadata = tomli.load(f)
|
||||||
|
self._metadata_cache = metadata
|
||||||
|
logger.debug(f"Loaded metadata from {metadata_file}")
|
||||||
|
return metadata
|
||||||
|
else:
|
||||||
|
logger.debug(f"No metadata.toml found for {self.module_name} at {metadata_file}")
|
||||||
|
self._metadata_cache = {}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading metadata for {self.module_name}: {e}")
|
||||||
|
self._metadata_cache = {}
|
||||||
|
return {}
|
||||||
@ -56,9 +56,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="!conversations.length" class="chat-examples">
|
<div v-else-if="!conversations.length" class="chat-examples">
|
||||||
<img v-if="currentAgentMetadata?.icon" class="agent-icons" :src="currentAgentMetadata?.icon" alt="智能体图标" />
|
<div style="margin-bottom: 150px"></div>
|
||||||
<div v-else style="margin-bottom: 150px"></div>
|
<h1>您好,我是{{ currentAgentName }}!</h1>
|
||||||
<h1>您好,我是{{ currentAgentName }}!有什么可以帮您?</h1>
|
|
||||||
<!-- <h1>{{ currentAgent ? currentAgent.name : '请选择一个智能体开始对话' }}</h1>
|
<!-- <h1>{{ currentAgent ? currentAgent.name : '请选择一个智能体开始对话' }}</h1>
|
||||||
<p>{{ currentAgent ? currentAgent.description : '不同的智能体有不同的专长和能力' }}</p> -->
|
<p>{{ currentAgent ? currentAgent.description : '不同的智能体有不同的专长和能力' }}</p> -->
|
||||||
|
|
||||||
@ -190,7 +189,12 @@ const userInput = ref('');
|
|||||||
|
|
||||||
// 从智能体元数据获取示例问题
|
// 从智能体元数据获取示例问题
|
||||||
const exampleQuestions = computed(() => {
|
const exampleQuestions = computed(() => {
|
||||||
const examples = currentAgentMetadata.value?.examples || [];
|
const agentId = currentAgentId.value;
|
||||||
|
let examples = [];
|
||||||
|
if (agentId && agents.value && agents.value.length > 0) {
|
||||||
|
const agent = agents.value.find(a => a.id === agentId);
|
||||||
|
examples = agent ? (agent.examples || []) : [];
|
||||||
|
}
|
||||||
return examples.map((text, index) => ({
|
return examples.map((text, index) => ({
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
text: text
|
text: text
|
||||||
@ -234,12 +238,14 @@ const currentAgentId = computed(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentAgentMetadata = computed(() => {
|
const currentAgentName = computed(() => {
|
||||||
const agentId = currentAgentId.value;
|
const agentId = currentAgentId.value;
|
||||||
const metadata = agentStore?.metadata || {};
|
if (agentId && agents.value && agents.value.length > 0) {
|
||||||
return agentId && metadata[agentId] ? metadata[agentId] : {};
|
const agent = agents.value.find(a => a.id === agentId);
|
||||||
|
return agent ? agent.name : '智能体';
|
||||||
|
}
|
||||||
|
return '智能体';
|
||||||
});
|
});
|
||||||
const currentAgentName = computed(() => currentAgentMetadata.value?.name || currentAgent.value?.name || '智能体');
|
|
||||||
|
|
||||||
const currentAgent = computed(() => agents.value[currentAgentId.value] || null);
|
const currentAgent = computed(() => agents.value[currentAgentId.value] || null);
|
||||||
const chatsList = computed(() => threads.value || []);
|
const chatsList = computed(() => threads.value || []);
|
||||||
@ -947,10 +953,17 @@ const handleExampleClick = (questionText) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const buildExportPayload = () => {
|
const buildExportPayload = () => {
|
||||||
|
const agentId = currentAgentId.value;
|
||||||
|
let agentDescription = '';
|
||||||
|
if (agentId && agents.value && agents.value.length > 0) {
|
||||||
|
const agent = agents.value.find(a => a.id === agentId);
|
||||||
|
agentDescription = agent ? (agent.description || '') : '';
|
||||||
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
chatTitle: currentThread.value?.title || '新对话',
|
chatTitle: currentThread.value?.title || '新对话',
|
||||||
agentName: currentAgentName.value || currentAgent.value?.name || '智能助手',
|
agentName: currentAgentName.value || currentAgent.value?.name || '智能助手',
|
||||||
agentDescription: currentAgentMetadata.value?.description || currentAgent.value?.description || '',
|
agentDescription: agentDescription || currentAgent.value?.description || '',
|
||||||
messages: conversations.value ? JSON.parse(JSON.stringify(conversations.value)) : [],
|
messages: conversations.value ? JSON.parse(JSON.stringify(conversations.value)) : [],
|
||||||
onGoingMessages: onGoingConvMessages.value ? JSON.parse(JSON.stringify(onGoingConvMessages.value)) : []
|
onGoingMessages: onGoingConvMessages.value ? JSON.parse(JSON.stringify(onGoingConvMessages.value)) : []
|
||||||
};
|
};
|
||||||
|
|||||||
@ -100,8 +100,8 @@ const props = defineProps({
|
|||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
agents: {
|
agents: {
|
||||||
type: Object,
|
type: Array,
|
||||||
default: () => ({})
|
default: () => []
|
||||||
},
|
},
|
||||||
selectedAgentId: {
|
selectedAgentId: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -112,8 +112,9 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['create-chat', 'select-chat', 'delete-chat', 'rename-chat', 'toggle-sidebar', 'open-agent-modal']);
|
const emit = defineEmits(['create-chat', 'select-chat', 'delete-chat', 'rename-chat', 'toggle-sidebar', 'open-agent-modal']);
|
||||||
|
|
||||||
const selectedAgentName = computed(() => {
|
const selectedAgentName = computed(() => {
|
||||||
if (props.selectedAgentId && props.agents && props.agents[props.selectedAgentId]) {
|
if (props.selectedAgentId && props.agents && props.agents.length > 0) {
|
||||||
return props.agents[props.selectedAgentId].name;
|
const agent = props.agents.find(a => a.id === props.selectedAgentId);
|
||||||
|
return agent ? agent.name : '';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import { handleChatError } from '@/utils/errorHandler';
|
|||||||
export const useAgentStore = defineStore('agent', {
|
export const useAgentStore = defineStore('agent', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
// 智能体相关状态
|
// 智能体相关状态
|
||||||
agents: {}, // 以ID为键的智能体对象
|
agents: [], // 智能体数组,每个元素包含完整信息
|
||||||
metadata: {}, // 智能体元数据
|
|
||||||
selectedAgentId: null, // 当前选中的智能体ID
|
selectedAgentId: null, // 当前选中的智能体ID
|
||||||
defaultAgentId: null, // 默认智能体ID
|
defaultAgentId: null, // 默认智能体ID
|
||||||
|
|
||||||
@ -34,12 +33,12 @@ export const useAgentStore = defineStore('agent', {
|
|||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
// --- 智能体相关 Getters ---
|
// --- 智能体相关 Getters ---
|
||||||
selectedAgent: (state) => state.selectedAgentId ? state.agents[state.selectedAgentId] : null,
|
selectedAgent: (state) => state.selectedAgentId ? state.agents.find(a => a.id === state.selectedAgentId) : null,
|
||||||
defaultAgent: (state) => state.defaultAgentId ? state.agents[state.defaultAgentId] : state.agents[Object.keys(state.agents)[0]],
|
defaultAgent: (state) => state.defaultAgentId ? state.agents.find(a => a.id === state.defaultAgentId) : state.agents[0],
|
||||||
agentsList: (state) => Object.values(state.agents),
|
agentsList: (state) => state.agents,
|
||||||
isDefaultAgent: (state) => state.selectedAgentId === state.defaultAgentId,
|
isDefaultAgent: (state) => state.selectedAgentId === state.defaultAgentId,
|
||||||
configurableItems: (state) => {
|
configurableItems: (state) => {
|
||||||
const agent = state.selectedAgentId ? state.agents[state.selectedAgentId] : null;
|
const agent = state.selectedAgentId ? state.agents.find(a => a.id === state.selectedAgentId) : null;
|
||||||
if (!agent || !agent.configurable_items) return {};
|
if (!agent || !agent.configurable_items) return {};
|
||||||
|
|
||||||
const agentConfigurableItems = agent.configurable_items;
|
const agentConfigurableItems = agent.configurable_items;
|
||||||
@ -67,11 +66,11 @@ export const useAgentStore = defineStore('agent', {
|
|||||||
await this.fetchAgents();
|
await this.fetchAgents();
|
||||||
await this.fetchDefaultAgent();
|
await this.fetchDefaultAgent();
|
||||||
|
|
||||||
if (!this.selectedAgentId || !this.agents[this.selectedAgentId]) {
|
if (!this.selectedAgentId || !this.agents.find(a => a.id === this.selectedAgentId)) {
|
||||||
if (this.defaultAgentId && this.agents[this.defaultAgentId]) {
|
if (this.defaultAgentId && this.agents.find(a => a.id === this.defaultAgentId)) {
|
||||||
this.selectAgent(this.defaultAgentId);
|
this.selectAgent(this.defaultAgentId);
|
||||||
} else if (Object.keys(this.agents).length > 0) {
|
} else if (this.agents.length > 0) {
|
||||||
const firstAgentId = Object.keys(this.agents)[0];
|
const firstAgentId = this.agents[0].id;
|
||||||
this.selectAgent(firstAgentId);
|
this.selectAgent(firstAgentId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -98,12 +97,8 @@ export const useAgentStore = defineStore('agent', {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await agentApi.getAgents();
|
const response = await agentApi.getAgents();
|
||||||
// 将数组转换为以ID为键的对象
|
// 直接使用返回的 agents 数组
|
||||||
this.agents = response.agents.reduce((acc, agent) => {
|
this.agents = response.agents;
|
||||||
acc[agent.id] = agent;
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
this.metadata = response.metadata;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch agents:', error);
|
console.error('Failed to fetch agents:', error);
|
||||||
handleChatError(error, 'fetch');
|
handleChatError(error, 'fetch');
|
||||||
@ -141,7 +136,7 @@ export const useAgentStore = defineStore('agent', {
|
|||||||
|
|
||||||
// 选择智能体
|
// 选择智能体
|
||||||
selectAgent(agentId) {
|
selectAgent(agentId) {
|
||||||
if (this.agents[agentId]) {
|
if (this.agents.find(a => a.id === agentId)) {
|
||||||
this.selectedAgentId = agentId;
|
this.selectedAgentId = agentId;
|
||||||
// 清空之前的配置
|
// 清空之前的配置
|
||||||
this.agentConfig = {};
|
this.agentConfig = {};
|
||||||
@ -229,7 +224,7 @@ export const useAgentStore = defineStore('agent', {
|
|||||||
|
|
||||||
// 重置store状态
|
// 重置store状态
|
||||||
reset() {
|
reset() {
|
||||||
this.agents = {};
|
this.agents = [];
|
||||||
this.selectedAgentId = null;
|
this.selectedAgentId = null;
|
||||||
this.defaultAgentId = null;
|
this.defaultAgentId = null;
|
||||||
this.agentConfig = {};
|
this.agentConfig = {};
|
||||||
|
|||||||
@ -13,20 +13,23 @@
|
|||||||
<div class="agent-modal-content">
|
<div class="agent-modal-content">
|
||||||
<div class="agents-grid">
|
<div class="agents-grid">
|
||||||
<div
|
<div
|
||||||
v-for="(agent, id) in agents"
|
v-for="agent in agents"
|
||||||
:key="id"
|
:key="agent.id"
|
||||||
class="agent-card"
|
class="agent-card"
|
||||||
:class="{ 'selected': id === selectedAgentId }"
|
:class="{ 'selected': agent.id === selectedAgentId }"
|
||||||
@click="selectAgentFromModal(id)"
|
@click="selectAgentFromModal(agent.id)"
|
||||||
>
|
>
|
||||||
<div class="agent-card-header">
|
<div class="agent-card-header">
|
||||||
<div class="agent-card-title">
|
<div class="agent-card-title">
|
||||||
<span class="agent-card-name">{{ agent.name }}</span>
|
<span class="agent-card-name">{{ agent.name || 'Unknown' }}</span>
|
||||||
<StarFilled v-if="id === defaultAgentId" class="default-icon" />
|
<StarFilled v-if="agent.id === defaultAgentId" class="default-icon" />
|
||||||
<StarOutlined v-else @click.prevent="setAsDefaultAgent(id)" class="default-icon" />
|
<StarOutlined v-else @click.prevent="setAsDefaultAgent(agent.id)" class="default-icon" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="agent-card-description">{{ agent.description }}</div>
|
|
||||||
|
<div class="agent-card-description">
|
||||||
|
{{ agent.description || '' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -97,7 +100,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, watch } from 'vue';
|
import { ref, reactive, watch, computed } from 'vue';
|
||||||
import {
|
import {
|
||||||
StarOutlined,
|
StarOutlined,
|
||||||
StarFilled,
|
StarFilled,
|
||||||
@ -130,6 +133,7 @@ const {
|
|||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
defaultAgentId,
|
defaultAgentId,
|
||||||
} = storeToRefs(agentStore);
|
} = storeToRefs(agentStore);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
agentModalOpen: false,
|
agentModalOpen: false,
|
||||||
isConfigSidebarOpen: false,
|
isConfigSidebarOpen: false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user