fix(mention): 解决新会话中@提及无法激活问题,引入Redis缓存一致性失效闭环

This commit is contained in:
supreme0597 2026-05-22 13:15:46 +08:00 committed by Wenjie Zhang
parent 6b29f659e5
commit 9dcd8fdaa7
7 changed files with 16 additions and 28 deletions

View File

@ -16,7 +16,6 @@ from yuxi.repositories.user_repository import UserRepository
from yuxi.storage.postgres.manager import pg_manager
from yuxi.utils.logging_config import logger
ADMIN_ROLES = {"admin", "superadmin"}
SANDBOX_PATH_HINT = (
"请使用 /home/gem/user-data/workspace/...、/home/gem/user-data/uploads/... 或 /home/gem/user-data/outputs/..."

View File

@ -12,6 +12,7 @@ from yuxi.agents.buildin import agent_manager
from yuxi.config import config as app_config
from yuxi.plugins.parser import Parser
from yuxi.repositories.conversation_repository import ConversationRepository
from yuxi.services.mention_search_service import invalidate_mention_cache
from yuxi.services.upload_utils import write_upload_to_path
from yuxi.utils.datetime_utils import utc_isoformat
from yuxi.utils.logging_config import logger
@ -410,6 +411,8 @@ async def upload_thread_attachment_view(
attachments=all_attachments,
)
await invalidate_mention_cache(thread_id)
return serialize_attachment(attachment_record)
@ -474,6 +477,8 @@ async def delete_thread_attachment_view(
attachments=all_attachments,
)
await invalidate_mention_cache(thread_id)
return {"message": "附件已删除"}

View File

@ -17,6 +17,7 @@ from yuxi.agents.backends.sandbox import (
)
from yuxi.repositories.conversation_repository import ConversationRepository
from yuxi.services.conversation_service import require_user_conversation
from yuxi.services.mention_search_service import invalidate_mention_cache
from yuxi.utils.datetime_utils import utc_isoformat_from_timestamp
@ -255,6 +256,8 @@ async def save_thread_artifact_to_workspace_view(
with source_path.open("rb") as src, target_path.open("wb") as dst:
shutil.copyfileobj(src, dst)
await invalidate_mention_cache(thread_id)
saved_virtual_path = virtual_path_for_thread_file(thread_id, target_path, user_id=user_id)
return {
"name": target_path.name,

View File

@ -431,7 +431,6 @@ const currentTodos = computed(() => {
return Array.isArray(todos) ? todos : []
})
const { mentionConfig } = useAgentMentionConfig({
currentAgentState,
currentThreadAttachments,

View File

@ -321,7 +321,9 @@ const refreshFileSystem = async () => {
(entry) => entry?.is_dir && entry.name === DISPLAY_ROOT_DIRECTORY_NAME
)
dynamicTreeData.value = displayRootEntry ? await loadDirectoryChildren(displayRootEntry.path) : []
dynamicTreeData.value = displayRootEntry
? await loadDirectoryChildren(displayRootEntry.path)
: []
expandedKeys.value = []
selectedKeys.value = []
} else {

View File

@ -39,11 +39,7 @@
/>
<!-- @ 提及选择弹窗 -->
<div
v-if="mentionPopupVisible"
ref="mentionDropdownRef"
class="mention-dropdown-wrapper"
>
<div v-if="mentionPopupVisible" ref="mentionDropdownRef" class="mention-dropdown-wrapper">
<div class="mention-popup">
<!-- 文件列表 -->
<div v-if="mentionItems.files.length > 0 || showFileSearchPrompt" class="mention-group">
@ -259,15 +255,7 @@ const slots = useSlots()
// @
const mentionEnabled = computed(() => {
if (!props.mention) return false
const { files, knowledgeBases, mcps, skills, subagents } = props.mention
return (
(Array.isArray(files) && files.length > 0) ||
(Array.isArray(knowledgeBases) && knowledgeBases.length > 0) ||
(Array.isArray(mcps) && mcps.length > 0) ||
(Array.isArray(skills) && skills.length > 0) ||
(Array.isArray(subagents) && subagents.length > 0)
)
return !!props.mention
})
const mentionTypePrefixMap = {
@ -539,7 +527,6 @@ const hasAnyItems = computed(() => {
)
})
const insertMention = (item) => {
if (!inputRef.value) return
@ -1000,7 +987,9 @@ defineExpose({
overflow-y: auto;
background: var(--gray-0);
border-radius: 8px;
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.08), 0 4px 16px rgba(0, 0, 0, 0.12);
box-shadow:
0 -4px 16px rgba(0, 0, 0, 0.08),
0 4px 16px rgba(0, 0, 0, 0.12);
border: 1px solid var(--gray-200);
.mention-group {

View File

@ -127,15 +127,6 @@ export function useAgentMentionConfig({
}
)
if (
!files.length &&
!knowledgeBases.length &&
!mcps.length &&
!skills.length &&
!subagents.length
)
return null
return {
files,
knowledgeBases,