format: 格式化代码
This commit is contained in:
parent
e07e88ae49
commit
4df242e63b
@ -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
|
||||
|
||||
|
||||
@ -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]:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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: ...
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -21,6 +21,7 @@ from yuxi.services.subagent_service import get_subagents_from_names
|
||||
|
||||
from .prompt import PROMPT
|
||||
|
||||
|
||||
def _create_fs_backend(rt):
|
||||
"""创建文件存储后端(支持沙盒执行)
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -92,7 +92,7 @@ class BaseContext:
|
||||
default=sys_config.default_model,
|
||||
metadata={
|
||||
"name": "子智能体的默认模型",
|
||||
"description": "子智能体的默认模型,会被子智能体的配置覆盖。",
|
||||
"description": "为所有子智能体设置默认模型,可在各子智能体配置中单独覆盖。",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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"
|
||||
)
|
||||
|
||||
|
||||
@ -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 = () => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -298,7 +298,6 @@
|
||||
</a-spin>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
|
||||
</a-tabs>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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'
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user