format: 格式化代码

This commit is contained in:
Wenjie Zhang 2026-03-24 22:37:03 +08:00
parent e07e88ae49
commit 4df242e63b
23 changed files with 76 additions and 93 deletions

View File

@ -27,9 +27,9 @@ from .sandbox import (
get_sandbox_base_port,
get_sandbox_host,
get_sandbox_image,
get_sandbox_provider,
get_sandbox_provisioner_url,
get_sandbox_security_opts,
get_sandbox_provider,
)
from .skills_backend import SelectedSkillsReadonlyBackend

View File

@ -4,8 +4,8 @@ from deepagents.backends import CompositeBackend, StateBackend
from yuxi.agents.middlewares.skills_middleware import normalize_selected_skills
from .skills_backend import SelectedSkillsReadonlyBackend
from .sandbox import get_sandbox_provider
from .skills_backend import SelectedSkillsReadonlyBackend
def _get_visible_skills_from_runtime(runtime) -> list[str]:

View File

@ -16,10 +16,7 @@
- docker_api: Docker API 调用封装
"""
from .sandbox_executor import YuxiSandboxBackend
from .sandbox_info import SandboxInfo
from .sandbox_provisioner import YuxiSandboxProvider, get_sandbox_provider
from .sandbox_provisioner_base import SandboxBackend
from .path_security import normalize_virtual_path
from .sandbox_config import (
IDLE_CHECK_INTERVAL,
LARGE_TOOL_RESULTS_DIR,
@ -39,9 +36,12 @@ from .sandbox_config import (
get_sandbox_provisioner_url,
get_sandbox_security_opts,
)
from .sandbox_executor import YuxiSandboxBackend
from .sandbox_info import SandboxInfo
from .sandbox_local_container import LocalContainerBackend
from .sandbox_provisioner import YuxiSandboxProvider, get_sandbox_provider
from .sandbox_provisioner_base import SandboxBackend
from .sandbox_remote import RemoteSandboxBackend
from .path_security import normalize_virtual_path
__all__ = [
# Executor

View File

@ -9,9 +9,9 @@ import urllib.parse
from yuxi.utils.logging_config import logger
from .docker_api import docker_api_request
from .sandbox_provisioner_base import SandboxBackend
from .sandbox_config import get_sandbox_host, get_sandbox_security_opts
from .sandbox_info import SandboxInfo
from .sandbox_provisioner_base import SandboxBackend
class LocalContainerBackend(SandboxBackend):

View File

@ -14,10 +14,6 @@ from yuxi import config as sys_config
from yuxi.services.skill_service import get_skills_root_dir
from yuxi.utils.logging_config import logger
from .sandbox_local_container import LocalContainerBackend
from .sandbox_remote import RemoteSandboxBackend
from .sandbox_executor import YuxiSandboxBackend
from .sandbox_provisioner_base import SandboxBackend
from .sandbox_config import (
IDLE_CHECK_INTERVAL,
LARGE_TOOL_RESULTS_DIR,
@ -34,7 +30,11 @@ from .sandbox_config import (
get_sandbox_image,
get_sandbox_provisioner_url,
)
from .sandbox_executor import YuxiSandboxBackend
from .sandbox_info import SandboxInfo
from .sandbox_local_container import LocalContainerBackend
from .sandbox_provisioner_base import SandboxBackend
from .sandbox_remote import RemoteSandboxBackend
class YuxiSandboxProvider:
@ -259,9 +259,7 @@ class YuxiSandboxProvider:
self._last_activity.pop(sandbox_id, None)
self._warm_pool.pop(sandbox_id, None)
thread_ids = [
thread_id
for thread_id, mapped_id in self._thread_sandboxes.items()
if mapped_id == sandbox_id
thread_id for thread_id, mapped_id in self._thread_sandboxes.items() if mapped_id == sandbox_id
]
for thread_id in thread_ids:
del self._thread_sandboxes[thread_id]

View File

@ -13,17 +13,13 @@ class SandboxBackend(ABC):
thread_id: str,
sandbox_id: str,
extra_mounts: list[tuple[str, str, bool]] | None = None,
) -> SandboxInfo:
...
) -> SandboxInfo: ...
@abstractmethod
def destroy(self, info: SandboxInfo) -> None:
...
def destroy(self, info: SandboxInfo) -> None: ...
@abstractmethod
def is_alive(self, info: SandboxInfo) -> bool:
...
def is_alive(self, info: SandboxInfo) -> bool: ...
@abstractmethod
def discover(self, sandbox_id: str) -> SandboxInfo | None:
...
def discover(self, sandbox_id: str) -> SandboxInfo | None: ...

View File

@ -6,8 +6,8 @@ import requests
from yuxi.utils.logging_config import logger
from .sandbox_provisioner_base import SandboxBackend
from .sandbox_info import SandboxInfo
from .sandbox_provisioner_base import SandboxBackend
class RemoteSandboxBackend(SandboxBackend):

View File

@ -21,6 +21,7 @@ from yuxi.services.subagent_service import get_subagents_from_names
from .prompt import PROMPT
def _create_fs_backend(rt):
"""创建文件存储后端(支持沙盒执行)

View File

@ -39,11 +39,7 @@ class DeepAgent(BaseAgent):
description = "具备规划、深度分析和子智能体协作能力的智能体,可以处理复杂的多步骤任务"
context_schema = DeepContext
capabilities = ["file_upload", "files", "todo"] # 支持文件上传功能
metadata = {
"examples": [
"调研一下多模态 GraphRAG 的相关论文"
]
}
metadata = {"examples": ["调研一下多模态 GraphRAG 的相关论文"]}
def __init__(self, **kwargs):
super().__init__(**kwargs)

View File

@ -92,7 +92,7 @@ class BaseContext:
default=sys_config.default_model,
metadata={
"name": "子智能体的默认模型",
"description": "子智能体的默认模型,会被子智能体的配置覆盖。",
"description": "为所有子智能体设置默认模型,可在各子智能体配置中单独覆盖。",
},
)

View File

@ -404,9 +404,8 @@ class SkillsMiddleware(AgentMiddleware):
return None
pure = PurePosixPath(raw if raw.startswith("/") else f"/{raw}")
parts = [p for p in pure.parts if p not in ("/", "")]
if len(parts) == 3 and parts[0] == "skills" and parts[2] == "SKILL.md":
slug = parts[1]
elif len(parts) == 4 and parts[0] == "mnt" and parts[1] == "skills" and parts[3] == "SKILL.md":
# 只支持 /mnt/skills/{slug}/SKILL.md 格式
if len(parts) == 4 and parts[0] == "mnt" and parts[1] == "skills" and parts[3] == "SKILL.md":
slug = parts[2]
else:
return None

View File

@ -4,15 +4,15 @@ import asyncio
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from yuxi.agents.context import BaseContext
from yuxi.agents.backends import (
create_agent_composite_backend,
resolve_sandbox_backend_async,
)
from yuxi.agents.context import BaseContext
from yuxi.repositories.agent_config_repository import AgentConfigRepository
from yuxi.repositories.conversation_repository import ConversationRepository
from yuxi.storage.postgres.models_business import User
from yuxi.services.conversation_service import require_user_conversation
from yuxi.storage.postgres.models_business import User
async def _resolve_filesystem_context(

View File

@ -9,12 +9,11 @@ from urllib.parse import quote
from fastapi import HTTPException
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from yuxi.agents.backends.sandbox import SKILLS_PATH, USER_DATA_PATH
from yuxi.agents.backends.skills_backend import SelectedSkillsReadonlyBackend
from yuxi.agents.middlewares.skills_middleware import normalize_selected_skills
from yuxi.storage.postgres.models_business import User
from yuxi.services.filesystem_service import _resolve_filesystem_state
from yuxi.storage.postgres.models_business import User
def _normalize_path(path: str | None) -> str:
@ -117,9 +116,7 @@ async def list_viewer_filesystem_tree(
)
if normalized_path == "/":
entries = [
{"path": f"{USER_DATA_PATH}/", "name": "user-data", "is_dir": True, "size": 0, "modified_at": ""}
]
entries = [{"path": f"{USER_DATA_PATH}/", "name": "user-data", "is_dir": True, "size": 0, "modified_at": ""}]
if selected_skills:
entries.append({"path": f"{SKILLS_PATH}/", "name": "skills", "is_dir": True, "size": 0, "modified_at": ""})
return {"entries": entries}

View File

@ -67,7 +67,7 @@ $images = @(
"ghcr.io/astral-sh/uv:0.7.2",
"nginx:alpine",
"quay.io/coreos/etcd:v3.5.5",
"postgres:16"
"postgres:16",
"redis:7-alpine"
)

View File

@ -476,7 +476,9 @@ const isStreaming = computed(() => {
})
const isProcessing = computed(() => isStreaming.value)
const isSendButtonDisabled = computed(() => {
return sendCooldownActive.value || (((!userInput.value || !currentAgent.value) && !isProcessing.value))
return (
sendCooldownActive.value || ((!userInput.value || !currentAgent.value) && !isProcessing.value)
)
})
const startSendCooldown = () => {

View File

@ -58,11 +58,7 @@
<!-- <a-divider /> -->
<div class="config-segment" v-if="!isEmptyConfig">
<a-segmented
v-model:value="currentSegment"
:options="segmentOptions"
block
/>
<a-segmented v-model:value="currentSegment" :options="segmentOptions" block />
</div>
<div
@ -571,15 +567,15 @@ const hasOtherConfigs = computed(() => {
const segmentConfigKeys = computed(() => {
const keys = Object.keys(configurableItems.value)
return {
model: keys.filter(key => {
model: keys.filter((key) => {
const meta = configurableItems.value[key]?.template_metadata?.kind
return meta === 'llm' || meta === 'prompt'
}),
tools: keys.filter(key => {
tools: keys.filter((key) => {
const meta = configurableItems.value[key]?.template_metadata?.kind
return ['tools', 'knowledges', 'mcps', 'skills', 'subagents'].includes(meta)
}),
other: keys.filter(key => {
other: keys.filter((key) => {
const meta = configurableItems.value[key]?.template_metadata?.kind
return !['llm', 'prompt', 'tools', 'knowledges', 'mcps', 'skills', 'subagents'].includes(meta)
})
@ -590,7 +586,7 @@ const filteredConfigurableItems = computed(() => {
if (isEmptyConfig.value) return {}
const keys = segmentConfigKeys.value[currentSegment.value] || []
const filtered = {}
keys.forEach(key => {
keys.forEach((key) => {
filtered[key] = configurableItems.value[key]
})
return filtered

View File

@ -136,7 +136,9 @@
<pre v-if="Array.isArray(currentFile?.content)">{{
formatContent(currentFile.content)
}}</pre>
<pre v-else-if="typeof currentFile?.content === 'string'" class="file-content-pre">{{ currentFile.content }}</pre>
<pre v-else-if="typeof currentFile?.content === 'string'" class="file-content-pre">{{
currentFile.content
}}</pre>
<pre v-else>{{ JSON.stringify(currentFile, null, 2) }}</pre>
</template>
</div>
@ -392,7 +394,12 @@ const refreshFileSystem = async () => {
loadingFiles.value = true
filesystemError.value = ''
try {
const res = await getViewerFileSystemTree(props.threadId, '/', props.agentId, props.agentConfigId)
const res = await getViewerFileSystemTree(
props.threadId,
'/',
props.agentId,
props.agentConfigId
)
if (res && res.entries) {
dynamicTreeData.value = sortEntries(res.entries).map((entry) => createTreeNode(entry))
expandedKeys.value = []
@ -413,19 +420,16 @@ onMounted(() => {
refreshFileSystem()
})
watch(
[() => props.threadId, () => props.agentId, () => props.agentConfigId],
([threadId]) => {
if (threadId) {
refreshFileSystem()
} else {
dynamicTreeData.value = []
expandedKeys.value = []
selectedKeys.value = []
filesystemError.value = ''
}
watch([() => props.threadId, () => props.agentId, () => props.agentConfigId], ([threadId]) => {
if (threadId) {
refreshFileSystem()
} else {
dynamicTreeData.value = []
expandedKeys.value = []
selectedKeys.value = []
filesystemError.value = ''
}
)
})
const fileTreeData = computed(() => dynamicTreeData.value)

View File

@ -298,7 +298,6 @@
</a-spin>
</div>
</a-tab-pane>
</a-tabs>
</template>
</div>

View File

@ -1,16 +1,13 @@
<template>
<div class="model-providers-section">
<div class="header-section">
<div class="header-content">
<div class="section-title">自定义供应商</div>
<p class="section-description">
添加自定义的LLM供应商支持OpenAI兼容的API格式
</p>
<p class="section-description">添加自定义的LLM供应商支持OpenAI兼容的API格式</p>
</div>
<a-button type="primary" @click="openAddCustomProviderModal" class="add-btn lucide-icon-btn">
<template #icon>
<Plus :size="16" />
<Plus :size="16" />
</template>
添加自定义供应商
</a-button>
@ -103,7 +100,9 @@
<span class="stats-item unavailable"> {{ notModelKeys.length }} 未配置 </span>
</div>
</div>
<p class="section-description">请在 <code>.env</code> 文件中配置对应的 APIKEY并重新启动服务</p>
<p class="section-description">
请在 <code>.env</code> 文件中配置对应的 APIKEY并重新启动服务
</p>
<!-- 已配置的供应商 -->
<div
@ -174,9 +173,7 @@
:width="800"
>
<div v-if="providerConfig.loading" class="modal-loading-container">
<a-spin
:indicator="h(LoaderCircle, { size: 32, color: 'var(--main-color)' })"
/>
<a-spin :indicator="h(LoaderCircle, { size: 32, color: 'var(--main-color)' })" />
<div class="loading-text">正在获取模型列表...</div>
</div>
<div v-else class="modal-config-content">
@ -822,7 +819,6 @@ const testCustomProvider = async (providerId, modelName) => {
</script>
<style lang="less" scoped>
.custom-providers-section {
margin-bottom: 24px;
.custom-provider-card {
@ -918,7 +914,6 @@ const testCustomProvider = async (providerId, modelName) => {
}
.builtin-providers-section {
.section-header {
.providers-stats {
display: flex;

View File

@ -64,12 +64,7 @@
<a-button v-else-if="showButton" type="primary" @click="goToLogin"> 登录 </a-button>
<!-- 个人资料弹窗 -->
<a-modal
v-model:open="profileModalVisible"
:footer="null"
width="420px"
class="profile-modal"
>
<a-modal v-model:open="profileModalVisible" :footer="null" width="420px" class="profile-modal">
<div class="profile-content">
<!-- 头像区域 -->
<div class="avatar-section">
@ -92,7 +87,12 @@
@change="handleAvatarChange"
accept="image/*"
>
<a-button type="primary" class="lucide-icon-btn" size="small" :loading="avatarUploading">
<a-button
type="primary"
class="lucide-icon-btn"
size="small"
:loading="avatarUploading"
>
<template #icon><Upload size="14" /></template>
{{ userStore.avatar ? '更换头像' : '上传头像' }}
</a-button>
@ -143,7 +143,7 @@
</div>
<div class="info-item">
<div class="info-label">角色</div>
<div class="info-value" :style="{'color': getRoleColor(userStore.userRole) }">
<div class="info-value" :style="{ color: getRoleColor(userStore.userRole) }">
{{ userRoleText }}
</div>
</div>

View File

@ -4,7 +4,9 @@
<div class="header-section">
<div class="header-content">
<div class="section-title">用户管理</div>
<p class="section-description">管理系统用户请谨慎操作删除用户后该用户将无法登录系统</p>
<p class="section-description">
管理系统用户请谨慎操作删除用户后该用户将无法登录系统
</p>
</div>
<a-button type="primary" @click="showAddUserModal" class="add-btn lucide-icon-btn">
<template #icon><Plus :size="16" /></template>

View File

@ -155,9 +155,7 @@ const initToolsChart = () => {
toolsChart = echarts.init(toolsChartRef.value)
const data = [...props.toolStats.most_used_tools]
.sort((a, b) => a.count - b.count)
.slice(0, 10) // 10
const data = [...props.toolStats.most_used_tools].sort((a, b) => a.count - b.count).slice(0, 10) // 10
const option = {
tooltip: {

View File

@ -62,7 +62,9 @@
</p>
<h1 class="title reveal-up delay-1">{{ infoStore.branding.title }}</h1>
<Transition name="subtitle-switch" mode="out-in">
<p v-if="currentSubtitle" class="subtitle" :key="currentSubtitle">{{ currentSubtitle }}</p>
<p v-if="currentSubtitle" class="subtitle" :key="currentSubtitle">
{{ currentSubtitle }}
</p>
</Transition>
<!-- <p class="description">{{ infoStore.branding.description }}</p> -->
<div class="hero-actions">
@ -281,9 +283,7 @@ const getHeroBadgeText = (starsCount = null) => {
}
const starValue =
typeof starFeature === 'string'
? ''
: (starFeature?.value || '').toString().trim()
typeof starFeature === 'string' ? '' : (starFeature?.value || '').toString().trim()
return starValue ? `已获得 ${starValue} GitHub Stars` : '已获得 GitHub Stars'
}