fix(mention): 解决新会话中@提及无法激活问题,引入Redis缓存一致性失效闭环
This commit is contained in:
parent
6b29f659e5
commit
9dcd8fdaa7
@ -16,7 +16,6 @@ from yuxi.repositories.user_repository import UserRepository
|
|||||||
from yuxi.storage.postgres.manager import pg_manager
|
from yuxi.storage.postgres.manager import pg_manager
|
||||||
from yuxi.utils.logging_config import logger
|
from yuxi.utils.logging_config import logger
|
||||||
|
|
||||||
|
|
||||||
ADMIN_ROLES = {"admin", "superadmin"}
|
ADMIN_ROLES = {"admin", "superadmin"}
|
||||||
SANDBOX_PATH_HINT = (
|
SANDBOX_PATH_HINT = (
|
||||||
"请使用 /home/gem/user-data/workspace/...、/home/gem/user-data/uploads/... 或 /home/gem/user-data/outputs/..."
|
"请使用 /home/gem/user-data/workspace/...、/home/gem/user-data/uploads/... 或 /home/gem/user-data/outputs/..."
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from yuxi.agents.buildin import agent_manager
|
|||||||
from yuxi.config import config as app_config
|
from yuxi.config import config as app_config
|
||||||
from yuxi.plugins.parser import Parser
|
from yuxi.plugins.parser import Parser
|
||||||
from yuxi.repositories.conversation_repository import ConversationRepository
|
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.services.upload_utils import write_upload_to_path
|
||||||
from yuxi.utils.datetime_utils import utc_isoformat
|
from yuxi.utils.datetime_utils import utc_isoformat
|
||||||
from yuxi.utils.logging_config import logger
|
from yuxi.utils.logging_config import logger
|
||||||
@ -410,6 +411,8 @@ async def upload_thread_attachment_view(
|
|||||||
attachments=all_attachments,
|
attachments=all_attachments,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await invalidate_mention_cache(thread_id)
|
||||||
|
|
||||||
return serialize_attachment(attachment_record)
|
return serialize_attachment(attachment_record)
|
||||||
|
|
||||||
|
|
||||||
@ -474,6 +477,8 @@ async def delete_thread_attachment_view(
|
|||||||
attachments=all_attachments,
|
attachments=all_attachments,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await invalidate_mention_cache(thread_id)
|
||||||
|
|
||||||
return {"message": "附件已删除"}
|
return {"message": "附件已删除"}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ from yuxi.agents.backends.sandbox import (
|
|||||||
)
|
)
|
||||||
from yuxi.repositories.conversation_repository import ConversationRepository
|
from yuxi.repositories.conversation_repository import ConversationRepository
|
||||||
from yuxi.services.conversation_service import require_user_conversation
|
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
|
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:
|
with source_path.open("rb") as src, target_path.open("wb") as dst:
|
||||||
shutil.copyfileobj(src, 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)
|
saved_virtual_path = virtual_path_for_thread_file(thread_id, target_path, user_id=user_id)
|
||||||
return {
|
return {
|
||||||
"name": target_path.name,
|
"name": target_path.name,
|
||||||
|
|||||||
@ -431,7 +431,6 @@ const currentTodos = computed(() => {
|
|||||||
return Array.isArray(todos) ? todos : []
|
return Array.isArray(todos) ? todos : []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const { mentionConfig } = useAgentMentionConfig({
|
const { mentionConfig } = useAgentMentionConfig({
|
||||||
currentAgentState,
|
currentAgentState,
|
||||||
currentThreadAttachments,
|
currentThreadAttachments,
|
||||||
|
|||||||
@ -321,7 +321,9 @@ const refreshFileSystem = async () => {
|
|||||||
(entry) => entry?.is_dir && entry.name === DISPLAY_ROOT_DIRECTORY_NAME
|
(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 = []
|
expandedKeys.value = []
|
||||||
selectedKeys.value = []
|
selectedKeys.value = []
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -39,11 +39,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- @ 提及选择弹窗 -->
|
<!-- @ 提及选择弹窗 -->
|
||||||
<div
|
<div v-if="mentionPopupVisible" ref="mentionDropdownRef" class="mention-dropdown-wrapper">
|
||||||
v-if="mentionPopupVisible"
|
|
||||||
ref="mentionDropdownRef"
|
|
||||||
class="mention-dropdown-wrapper"
|
|
||||||
>
|
|
||||||
<div class="mention-popup">
|
<div class="mention-popup">
|
||||||
<!-- 文件列表 -->
|
<!-- 文件列表 -->
|
||||||
<div v-if="mentionItems.files.length > 0 || showFileSearchPrompt" class="mention-group">
|
<div v-if="mentionItems.files.length > 0 || showFileSearchPrompt" class="mention-group">
|
||||||
@ -259,15 +255,7 @@ const slots = useSlots()
|
|||||||
|
|
||||||
// @ 提及功能是否启用
|
// @ 提及功能是否启用
|
||||||
const mentionEnabled = computed(() => {
|
const mentionEnabled = computed(() => {
|
||||||
if (!props.mention) return false
|
return !!props.mention
|
||||||
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)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const mentionTypePrefixMap = {
|
const mentionTypePrefixMap = {
|
||||||
@ -539,7 +527,6 @@ const hasAnyItems = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const insertMention = (item) => {
|
const insertMention = (item) => {
|
||||||
if (!inputRef.value) return
|
if (!inputRef.value) return
|
||||||
|
|
||||||
@ -1000,7 +987,9 @@ defineExpose({
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
background: var(--gray-0);
|
background: var(--gray-0);
|
||||||
border-radius: 8px;
|
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);
|
border: 1px solid var(--gray-200);
|
||||||
|
|
||||||
.mention-group {
|
.mention-group {
|
||||||
|
|||||||
@ -127,15 +127,6 @@ export function useAgentMentionConfig({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
|
||||||
!files.length &&
|
|
||||||
!knowledgeBases.length &&
|
|
||||||
!mcps.length &&
|
|
||||||
!skills.length &&
|
|
||||||
!subagents.length
|
|
||||||
)
|
|
||||||
return null
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
files,
|
files,
|
||||||
knowledgeBases,
|
knowledgeBases,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user