style: code format

This commit is contained in:
Wenjie Zhang 2026-03-29 13:49:54 +08:00
parent b7e10c6666
commit 90e3a79a77
10 changed files with 151 additions and 45 deletions

View File

@ -124,9 +124,7 @@ def virtual_path_for_thread_file(thread_id: str, path: str | Path) -> str:
else: else:
workspace_relative = relative_path.as_posix() workspace_relative = relative_path.as_posix()
relative_path_str = ( relative_path_str = (
_WORKSPACE_DIR_NAME _WORKSPACE_DIR_NAME if workspace_relative in {"", "."} else f"{_WORKSPACE_DIR_NAME}/{workspace_relative}"
if workspace_relative in {"", "."}
else f"{_WORKSPACE_DIR_NAME}/{workspace_relative}"
) )
prefix = get_virtual_path_prefix().rstrip("/") prefix = get_virtual_path_prefix().rstrip("/")

View File

@ -8,8 +8,7 @@ import requests
from langchain.tools import InjectedToolCallId from langchain.tools import InjectedToolCallId
from langchain_core.messages import ToolMessage from langchain_core.messages import ToolMessage
from langgraph.prebuilt.tool_node import ToolRuntime from langgraph.prebuilt.tool_node import ToolRuntime
from langgraph.types import Command from langgraph.types import Command, interrupt
from langgraph.types import interrupt
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from yuxi import config, graph_base from yuxi import config, graph_base

View File

@ -516,7 +516,9 @@ async def delete_mcp_server(db: AsyncSession, name: str) -> bool:
# ============================================================================= # =============================================================================
async def set_server_enabled(db: AsyncSession, name: str, enabled: bool, updated_by: str = None) -> tuple[bool, MCPServer]: async def set_server_enabled(
db: AsyncSession, name: str, enabled: bool, updated_by: str = None
) -> tuple[bool, MCPServer]:
"""Set server enabled status.""" """Set server enabled status."""
server = await get_mcp_server(db, name) server = await get_mcp_server(db, name)
if not server: if not server:

View File

@ -143,7 +143,12 @@ import hljs from 'highlight.js/lib/common'
import 'md-editor-v3/lib/preview.css' import 'md-editor-v3/lib/preview.css'
import { useThemeStore } from '@/stores/theme' import { useThemeStore } from '@/stores/theme'
import { getFileIcon, getFileIconColor } from '@/utils/file_utils' import { getFileIcon, getFileIconColor } from '@/utils/file_utils'
import { getCodeLanguageByPath, getPreviewTypeByPath, isHtmlPreview, isMarkdownPreview } from '@/utils/file_preview' import {
getCodeLanguageByPath,
getPreviewTypeByPath,
isHtmlPreview,
isMarkdownPreview
} from '@/utils/file_preview'
import { downloadViewerFile, getViewerFileContent } from '@/apis/viewer_filesystem' import { downloadViewerFile, getViewerFileContent } from '@/apis/viewer_filesystem'
const props = defineProps({ const props = defineProps({
@ -176,7 +181,9 @@ const normalizedArtifacts = computed(() =>
return { return {
path: normalizedPath, path: normalizedPath,
name: normalizedPath.split('/').pop() || normalizedPath, name: normalizedPath.split('/').pop() || normalizedPath,
canPreview: ['text', 'markdown', 'pdf', 'image'].includes(getPreviewTypeByPath(normalizedPath)) canPreview: ['text', 'markdown', 'pdf', 'image'].includes(
getPreviewTypeByPath(normalizedPath)
)
} }
}) })
) )

View File

@ -741,7 +741,8 @@ const getConfigOptions = (value) => {
return liveSkillOptions.value.length > 0 ? liveSkillOptions.value : value?.options || [] return liveSkillOptions.value.length > 0 ? liveSkillOptions.value : value?.options || []
} }
if (value?.template_metadata?.kind === 'subagents') { if (value?.template_metadata?.kind === 'subagents') {
const options = liveSubagentOptions.value.length > 0 ? liveSubagentOptions.value : value?.options || [] const options =
liveSubagentOptions.value.length > 0 ? liveSubagentOptions.value : value?.options || []
return options.filter((option) => option?.enabled !== false) return options.filter((option) => option?.enabled !== false)
} }
return value?.options || [] return value?.options || []

View File

@ -27,11 +27,17 @@
<!-- 服务器列表 --> <!-- 服务器列表 -->
<div class="list-container"> <div class="list-container">
<div v-if="!filteredEnabledServers.length && !filteredDisabledServers.length" class="empty-text"> <div
v-if="!filteredEnabledServers.length && !filteredDisabledServers.length"
class="empty-text"
>
<a-empty :image="false" :description="searchQuery ? '无匹配服务器' : '暂无服务器'" /> <a-empty :image="false" :description="searchQuery ? '无匹配服务器' : '暂无服务器'" />
</div> </div>
<div v-if="filteredEnabledServers.length" class="list-section-title">已添加</div> <div v-if="filteredEnabledServers.length" class="list-section-title">已添加</div>
<template v-for="(server, index) in filteredEnabledServers" :key="`enabled-${server.name}`"> <template
v-for="(server, index) in filteredEnabledServers"
:key="`enabled-${server.name}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentServer?.name === server.name }" :class="{ active: currentServer?.name === server.name }"
@ -44,7 +50,11 @@
</div> </div>
<div class="item-status"> <div class="item-status">
<span class="status-chip status-chip-success">已添加</span> <span class="status-chip status-chip-success">已添加</span>
<button type="button" class="inline-hover-action" @click.stop="handleSetServerEnabled(server, false)"> <button
type="button"
class="inline-hover-action"
@click.stop="handleSetServerEnabled(server, false)"
>
移除 移除
</button> </button>
</div> </div>
@ -62,7 +72,10 @@
></div> ></div>
</template> </template>
<div v-if="filteredDisabledServers.length" class="list-section-title">可添加</div> <div v-if="filteredDisabledServers.length" class="list-section-title">可添加</div>
<template v-for="(server, index) in filteredDisabledServers" :key="`disabled-${server.name}`"> <template
v-for="(server, index) in filteredDisabledServers"
:key="`disabled-${server.name}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentServer?.name === server.name, disabled: true }" :class="{ active: currentServer?.name === server.name, disabled: true }"
@ -74,7 +87,11 @@
<span class="item-name">{{ server.name }}</span> <span class="item-name">{{ server.name }}</span>
</div> </div>
<div class="item-status"> <div class="item-status">
<button type="button" class="skill-inline-action skill-inline-action-primary" @click.stop="handleSetServerEnabled(server, true)"> <button
type="button"
class="skill-inline-action skill-inline-action-primary"
@click.stop="handleSetServerEnabled(server, true)"
>
添加 添加
</button> </button>
</div> </div>
@ -556,8 +573,12 @@ const filteredServers = computed(() => {
) )
}) })
const filteredEnabledServers = computed(() => filteredServers.value.filter((item) => !!item.enabled)) const filteredEnabledServers = computed(() =>
const filteredDisabledServers = computed(() => filteredServers.value.filter((item) => !item.enabled)) filteredServers.value.filter((item) => !!item.enabled)
)
const filteredDisabledServers = computed(() =>
filteredServers.value.filter((item) => !item.enabled)
)
const isStdioTransport = computed( const isStdioTransport = computed(
() => () =>

View File

@ -19,13 +19,18 @@
<div class="list-container"> <div class="list-container">
<div <div
v-if="filteredInstalledSkills.length === 0 && filteredUninstalledBuiltinSkills.length === 0" v-if="
filteredInstalledSkills.length === 0 && filteredUninstalledBuiltinSkills.length === 0
"
class="empty-text" class="empty-text"
> >
<a-empty :image="false" description="无匹配技能" /> <a-empty :image="false" description="无匹配技能" />
</div> </div>
<div v-if="filteredInstalledSkills.length" class="list-section-title">已添加 Skills</div> <div v-if="filteredInstalledSkills.length" class="list-section-title">已添加 Skills</div>
<template v-for="(skill, index) in filteredInstalledSkills" :key="`installed-${skill.slug}`"> <template
v-for="(skill, index) in filteredInstalledSkills"
:key="`installed-${skill.slug}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentSkill?.slug === skill.slug }" :class="{ active: currentSkill?.slug === skill.slug }"
@ -38,7 +43,11 @@
</div> </div>
<div class="item-status"> <div class="item-status">
<span class="status-chip status-chip-success">已添加</span> <span class="status-chip status-chip-success">已添加</span>
<button type="button" class="inline-hover-action" @click.stop="confirmDeleteSkill(skill)"> <button
type="button"
class="inline-hover-action"
@click.stop="confirmDeleteSkill(skill)"
>
移除 移除
</button> </button>
</div> </div>
@ -46,18 +55,28 @@
<div class="item-details"> <div class="item-details">
<span class="item-desc">{{ skill.description || '暂无描述' }}</span> <span class="item-desc">{{ skill.description || '暂无描述' }}</span>
<div class="item-tags"> <div class="item-tags">
<span class="source-tag" :class="{ builtin: skill.sourceType === 'builtin' }">{{ skill.sourceLabel }}</span> <span class="source-tag" :class="{ builtin: skill.sourceType === 'builtin' }">{{
skill.sourceLabel
}}</span>
</div> </div>
</div> </div>
</div> </div>
<div <div
v-if="index < filteredInstalledSkills.length - 1 || filteredUninstalledBuiltinSkills.length > 0" v-if="
index < filteredInstalledSkills.length - 1 ||
filteredUninstalledBuiltinSkills.length > 0
"
class="list-separator" class="list-separator"
></div> ></div>
</template> </template>
<div v-if="filteredUninstalledBuiltinSkills.length" class="list-section-title">可添加 Skills</div> <div v-if="filteredUninstalledBuiltinSkills.length" class="list-section-title">
<template v-for="(skill, index) in filteredUninstalledBuiltinSkills" :key="`builtin-${skill.slug}`"> 可添加 Skills
</div>
<template
v-for="(skill, index) in filteredUninstalledBuiltinSkills"
:key="`builtin-${skill.slug}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentSkill?.slug === skill.slug }" :class="{ active: currentSkill?.slug === skill.slug }"
@ -85,7 +104,10 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="index < filteredUninstalledBuiltinSkills.length - 1" class="list-separator"></div> <div
v-if="index < filteredUninstalledBuiltinSkills.length - 1"
class="list-separator"
></div>
</template> </template>
</div> </div>
</div> </div>
@ -155,7 +177,9 @@
<div v-if="!isInstalledSkill" class="builtin-uninstalled-state"> <div v-if="!isInstalledSkill" class="builtin-uninstalled-state">
<h3>{{ currentSkill.description }}</h3> <h3>{{ currentSkill.description }}</h3>
<p>版本 {{ currentSkill.version }}</p> <p>版本 {{ currentSkill.version }}</p>
<a-button type="primary" @click="handleInstallBuiltin(currentSkill)">安装内置 Skill</a-button> <a-button type="primary" @click="handleInstallBuiltin(currentSkill)"
>安装内置 Skill</a-button
>
</div> </div>
<a-tabs v-else v-model:activeKey="activeTab" class="minimal-tabs"> <a-tabs v-else v-model:activeKey="activeTab" class="minimal-tabs">
@ -432,15 +456,23 @@ const installedSkillCards = computed(() => {
const filteredInstalledSkills = computed(() => installedSkillCards.value.filter(matchesSearch)) const filteredInstalledSkills = computed(() => installedSkillCards.value.filter(matchesSearch))
const filteredUninstalledBuiltinSkills = computed(() => { const filteredUninstalledBuiltinSkills = computed(() => {
return (builtinSkills.value || []).filter((skill) => skill.status === 'not_installed' && matchesSearch(skill)) return (builtinSkills.value || []).filter(
(skill) => skill.status === 'not_installed' && matchesSearch(skill)
)
}) })
const isInstalledSkill = computed(() => { const isInstalledSkill = computed(() => {
return !!(currentSkill.value && (currentSkill.value.installed_record || currentSkill.value.dir_path)) return !!(
currentSkill.value &&
(currentSkill.value.installed_record || currentSkill.value.dir_path)
)
}) })
const isBuiltinInstalledSkill = computed(() => { const isBuiltinInstalledSkill = computed(() => {
return !!(isInstalledSkill.value && (currentSkill.value?.is_builtin || currentSkill.value?.installed_record)) return !!(
isInstalledSkill.value &&
(currentSkill.value?.is_builtin || currentSkill.value?.installed_record)
)
}) })
const currentSkillStatusLabel = computed(() => { const currentSkillStatusLabel = computed(() => {
@ -642,7 +674,13 @@ const handleTreeSelect = async (keys, info) => {
} }
const saveCurrentFile = async () => { const saveCurrentFile = async () => {
if (!currentSkill.value || !selectedPath.value || selectedIsDir.value || isBuiltinInstalledSkill.value) return if (
!currentSkill.value ||
!selectedPath.value ||
selectedIsDir.value ||
isBuiltinInstalledSkill.value
)
return
savingFile.value = true savingFile.value = true
try { try {
await skillApi.updateSkillFile(currentSkill.value.slug, { await skillApi.updateSkillFile(currentSkill.value.slug, {
@ -746,11 +784,17 @@ const confirmDeleteSkill = (targetSkill = null) => {
const target = targetSkill || currentSkill.value const target = targetSkill || currentSkill.value
if (!target) return if (!target) return
const installed = const installed = !!(
!!(target && (target.installed_record || target.dir_path || target.is_builtin || target.sourceType)) target &&
(target.installed_record || target.dir_path || target.is_builtin || target.sourceType)
)
if (!installed) return if (!installed) return
const isBuiltinTarget = !!(target?.is_builtin || target?.installed_record || target?.sourceType === 'builtin') const isBuiltinTarget = !!(
target?.is_builtin ||
target?.installed_record ||
target?.sourceType === 'builtin'
)
const actionText = isBuiltinTarget ? '卸载' : '删除' const actionText = isBuiltinTarget ? '卸载' : '删除'
const detailText = isBuiltinTarget const detailText = isBuiltinTarget
? '卸载后会移除已安装文件和数据库记录,但仍可从“未安装 Skills”中重新安装。' ? '卸载后会移除已安装文件和数据库记录,但仍可从“未安装 Skills”中重新安装。'

View File

@ -20,11 +20,20 @@
<!-- SubAgent 列表 --> <!-- SubAgent 列表 -->
<div class="list-container"> <div class="list-container">
<div v-if="!filteredEnabledSubAgents.length && !filteredDisabledSubAgents.length" class="empty-text"> <div
<a-empty :image="false" :description="searchQuery ? '无匹配 SubAgent' : '暂无 SubAgent'" /> v-if="!filteredEnabledSubAgents.length && !filteredDisabledSubAgents.length"
class="empty-text"
>
<a-empty
:image="false"
:description="searchQuery ? '无匹配 SubAgent' : '暂无 SubAgent'"
/>
</div> </div>
<div v-if="filteredEnabledSubAgents.length" class="list-section-title">已添加</div> <div v-if="filteredEnabledSubAgents.length" class="list-section-title">已添加</div>
<template v-for="(agent, index) in filteredEnabledSubAgents" :key="`enabled-${agent.name}`"> <template
v-for="(agent, index) in filteredEnabledSubAgents"
:key="`enabled-${agent.name}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentAgent?.name === agent.name }" :class="{ active: currentAgent?.name === agent.name }"
@ -37,7 +46,11 @@
</div> </div>
<div class="item-status"> <div class="item-status">
<span class="status-chip status-chip-success">已添加</span> <span class="status-chip status-chip-success">已添加</span>
<button type="button" class="inline-hover-action danger" @click.stop="handleSetAgentEnabled(agent, false)"> <button
type="button"
class="inline-hover-action danger"
@click.stop="handleSetAgentEnabled(agent, false)"
>
移除 移除
</button> </button>
</div> </div>
@ -50,13 +63,18 @@
</div> </div>
</div> </div>
<div <div
v-if="index < filteredEnabledSubAgents.length - 1 || filteredDisabledSubAgents.length > 0" v-if="
index < filteredEnabledSubAgents.length - 1 || filteredDisabledSubAgents.length > 0
"
class="list-separator" class="list-separator"
></div> ></div>
</template> </template>
<div v-if="filteredDisabledSubAgents.length" class="list-section-title">可添加</div> <div v-if="filteredDisabledSubAgents.length" class="list-section-title">可添加</div>
<template v-for="(agent, index) in filteredDisabledSubAgents" :key="`disabled-${agent.name}`"> <template
v-for="(agent, index) in filteredDisabledSubAgents"
:key="`disabled-${agent.name}`"
>
<div <div
class="list-item extension-list-item" class="list-item extension-list-item"
:class="{ active: currentAgent?.name === agent.name }" :class="{ active: currentAgent?.name === agent.name }"
@ -68,7 +86,11 @@
<span class="item-name">{{ agent.name }}</span> <span class="item-name">{{ agent.name }}</span>
</div> </div>
<div class="item-status"> <div class="item-status">
<button type="button" class="skill-inline-action skill-inline-action-primary" @click.stop="handleSetAgentEnabled(agent, true)"> <button
type="button"
class="skill-inline-action skill-inline-action-primary"
@click.stop="handleSetAgentEnabled(agent, true)"
>
添加 添加
</button> </button>
</div> </div>
@ -172,7 +194,10 @@
</div> </div>
</div> </div>
<div class="detail-section" v-if="currentAgent.is_builtin || currentAgent.enabled === false"> <div
class="detail-section"
v-if="currentAgent.is_builtin || currentAgent.enabled === false"
>
<div class="section-header"> <div class="section-header">
<Info :size="14" /> <Info :size="14" />
<span>类型</span> <span>类型</span>
@ -325,8 +350,12 @@ const filteredSubAgents = computed(() => {
) )
}) })
const filteredEnabledSubAgents = computed(() => filteredSubAgents.value.filter((item) => item.enabled !== false)) const filteredEnabledSubAgents = computed(() =>
const filteredDisabledSubAgents = computed(() => filteredSubAgents.value.filter((item) => item.enabled === false)) filteredSubAgents.value.filter((item) => item.enabled !== false)
)
const filteredDisabledSubAgents = computed(() =>
filteredSubAgents.value.filter((item) => item.enabled === false)
)
// SubAgent // SubAgent
const fetchSubAgents = async () => { const fetchSubAgents = async () => {

View File

@ -71,7 +71,7 @@ const TOOL_RENDERERS = {
write_todos: TodoListTool write_todos: TodoListTool
} }
const TOOL_RENDERER_HIDE = ["present_artifacts"] const TOOL_RENDERER_HIDE = ['present_artifacts']
const currentRenderer = computed(() => TOOL_RENDERERS[toolId.value] || null) const currentRenderer = computed(() => TOOL_RENDERERS[toolId.value] || null)
const isHidden = computed(() => TOOL_RENDERER_HIDE.includes(toolId.value)) const isHidden = computed(() => TOOL_RENDERER_HIDE.includes(toolId.value))

View File

@ -20,7 +20,10 @@
<a-tooltip :title="`当前分类:${currentCategoryLabel}`"> <a-tooltip :title="`当前分类:${currentCategoryLabel}`">
<a-dropdown trigger="click"> <a-dropdown trigger="click">
<a-button class="sidebar-tool category-trigger" :class="{ active: !!selectedCategory }"> <a-button
class="sidebar-tool category-trigger"
:class="{ active: !!selectedCategory }"
>
<SlidersHorizontal :size="14" /> <SlidersHorizontal :size="14" />
</a-button> </a-button>
<template #overlay> <template #overlay>
@ -194,7 +197,9 @@ const filteredTools = computed(() => {
}) })
const currentCategoryLabel = computed( const currentCategoryLabel = computed(
() => categoryLabels[selectedCategory.value] || (selectedCategory.value ? selectedCategory.value : '全部分类') () =>
categoryLabels[selectedCategory.value] ||
(selectedCategory.value ? selectedCategory.value : '全部分类')
) )
const fetchTools = async () => { const fetchTools = async () => {