diff --git a/docs/.vitepress/theme/components/YuxiHome.vue b/docs/.vitepress/theme/components/YuxiHome.vue index c7bbf57d..5137ea81 100644 --- a/docs/.vitepress/theme/components/YuxiHome.vue +++ b/docs/.vitepress/theme/components/YuxiHome.vue @@ -503,6 +503,12 @@ open http://localhost:5173 .yx-home { --yx-max: 1152px; --yx-gap: 24px; + --yx-brand: var(--main-700); + --yx-brand-hover: var(--main-bright); + --yx-brand-soft: rgba(4, 106, 130, .12); + --yx-lime: #c6f43a; + --yx-lime-strong: #6f9300; + --yx-lime-soft: rgba(198, 244, 58, .24); color: var(--vp-c-text-1); font-size: 16px; line-height: 1.6; @@ -513,7 +519,7 @@ open http://localhost:5173 padding: 0 24px; } .yx-center { text-align: center; } -.yx-accent { color: var(--vp-c-brand-1); } +.yx-accent { color: var(--yx-brand); } /* 段落节奏 */ .yx-section { padding: 96px 0; } @@ -527,14 +533,14 @@ open http://localhost:5173 font-weight: 600; letter-spacing: .08em; text-transform: uppercase; - color: var(--vp-c-brand-1); + color: var(--yx-brand); margin-bottom: 12px; } .yx-head__title { font-size: 34px; font-weight: 700; line-height: 1.25; margin: 0; letter-spacing: -.01em; } .yx-head__sub { margin: 16px auto 0; color: var(--vp-c-text-2); font-size: 17px; } .yx-head__sub code, .yx-quick__tip code { font-size: .85em; padding: 2px 6px; border-radius: 6px; - background: var(--vp-c-bg-alt); color: var(--vp-c-brand-1); + background: var(--vp-c-bg-alt); color: var(--yx-brand); } /* ===== Hero ===== */ @@ -546,17 +552,17 @@ open http://localhost:5173 .yx-orb { position: absolute; border-radius: 50%; filter: blur(70px); will-change: transform; } .yx-orb--1 { width: 460px; height: 460px; top: -180px; right: -80px; - background: var(--vp-c-brand-soft); opacity: .6; + background: var(--yx-brand-soft); opacity: .6; animation: yxOrbFloat 18s ease-in-out infinite; } .yx-orb--2 { width: 380px; height: 380px; top: -120px; left: -120px; - background: var(--vp-c-brand-soft); opacity: .4; + background: var(--yx-lime-soft); opacity: .5; animation: yxOrbFloat 22s ease-in-out infinite reverse; } .yx-orb--3 { width: 320px; height: 320px; top: 30px; left: 46%; - background: var(--vp-c-brand-soft); opacity: .5; + background: var(--yx-brand-soft); opacity: .5; animation: yxOrbFloat 26s ease-in-out infinite; } .yx-grid { @@ -592,12 +598,12 @@ open http://localhost:5173 transition: transform .2s ease, background-color .2s ease, border-color .2s ease, color .2s ease; border: 1px solid transparent; text-decoration: none; } -.yx-btn--primary { background: var(--vp-c-brand-1); color: #fff; } -.yx-btn--primary:hover { background: var(--vp-c-brand-2); transform: translateY(-1px); } +.yx-btn--primary { background: var(--yx-brand); color: #fff; } +.yx-btn--primary:hover { background: var(--yx-brand-hover); transform: translateY(-1px); } .yx-btn--ghost { border-color: var(--vp-c-divider); color: var(--vp-c-text-1); background: var(--vp-c-bg); } -.yx-btn--ghost:hover { border-color: var(--vp-c-brand-1); color: var(--vp-c-brand-1); } +.yx-btn--ghost:hover { border-color: var(--yx-brand); color: var(--yx-brand); } .yx-btn--text { color: var(--vp-c-text-2); } -.yx-btn--text:hover { color: var(--vp-c-brand-1); } +.yx-btn--text:hover { color: var(--yx-brand); } .yx-hero__shot { margin-top: 56px; } .yx-hero__img { @@ -627,7 +633,7 @@ open http://localhost:5173 .yx-stat { text-align: center; padding: 32px 16px; } .yx-stat + .yx-stat { border-left: 1px solid var(--vp-c-divider); } .yx-stat__value { - font-size: 36px; font-weight: 800; color: var(--vp-c-brand-1); + font-size: 36px; font-weight: 800; color: var(--yx-brand); font-variant-numeric: tabular-nums; letter-spacing: -.02em; } .yx-stat__label { margin-top: 6px; font-size: 14px; color: var(--vp-c-text-2); } @@ -642,12 +648,12 @@ open http://localhost:5173 padding: 28px; background: var(--vp-c-bg); transition: transform .2s ease, border-color .2s ease; } -.yx-cap:hover { transform: translateY(-3px); border-color: var(--vp-c-brand-1); } +.yx-cap:hover { transform: translateY(-3px); border-color: var(--yx-brand); } .yx-cap--lg { grid-column: span 1; grid-row: span 2; display: flex; flex-direction: column; } .yx-cap__icon { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 12px; - background: var(--vp-c-brand-soft); color: var(--vp-c-brand-1); + background: var(--yx-brand-soft); color: var(--yx-brand); margin-bottom: 18px; } .yx-cap__icon svg { width: 22px; height: 22px; } @@ -681,9 +687,10 @@ open http://localhost:5173 .yx-list__ic { flex: none; width: 38px; height: 38px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center; - background: var(--vp-c-brand-soft); color: var(--vp-c-brand-1); + background: var(--yx-brand-soft); color: var(--yx-brand); } .yx-list__ic svg { width: 20px; height: 20px; } +.yx-tab--active .yx-list__ic { background: var(--yx-lime-soft); color: var(--yx-lime-strong); } .yx-tab__body { min-width: 0; } .yx-tab strong { display: block; font-size: 16px; } .yx-tab__desc { @@ -741,7 +748,7 @@ img.yx-engine-frame { object-fit: cover; } /* ===== 工作原理 ===== */ .yx-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--yx-gap); } .yx-step { position: relative; padding: 28px 24px; border: 1px solid var(--vp-c-divider); border-radius: 16px; background: var(--vp-c-bg); } -.yx-step__n { font-size: 26px; font-weight: 800; color: var(--vp-c-brand-1); font-variant-numeric: tabular-nums; } +.yx-step__n { font-size: 26px; font-weight: 800; color: var(--yx-brand); font-variant-numeric: tabular-nums; } .yx-step__title { font-size: 17px; font-weight: 700; margin: 10px 0 8px; } .yx-step__desc { margin: 0; color: var(--vp-c-text-2); font-size: 14px; } .yx-step__arrow { @@ -763,10 +770,10 @@ img.yx-engine-frame { object-fit: cover; } padding: 28px; background: var(--vp-c-bg); transition: transform .2s ease, border-color .2s ease; } -.yx-card:hover { transform: translateY(-3px); border-color: var(--vp-c-brand-1); } +.yx-card:hover { transform: translateY(-3px); border-color: var(--yx-brand); } .yx-card h3 { font-size: 18px; font-weight: 700; margin: 0 0 8px; } .yx-card p { margin: 0; color: var(--vp-c-text-2); font-size: 14.5px; } -.yx-card--case { border-left: 3px solid var(--vp-c-brand-1); } +.yx-card--case { border-left: 3px solid var(--yx-lime); } /* ===== 技术栈 ===== */ .yx-tech { max-width: 860px; margin: 0 auto; } @@ -796,7 +803,7 @@ img.yx-engine-frame { object-fit: cover; } .yx-contrib { display: block; max-width: 720px; margin: 0 auto; } .yx-contrib img { width: 100%; border-radius: 12px; } .yx-credits { margin: 32px 0 0; color: var(--vp-c-text-2); font-size: 14.5px; } -.yx-credits a { color: var(--vp-c-brand-1); text-decoration: none; } +.yx-credits a { color: var(--yx-brand); text-decoration: none; } .yx-credits a:hover { text-decoration: underline; } /* ===== 最终 CTA ===== */ diff --git a/docs/develop-guides/changelog.md b/docs/develop-guides/changelog.md index f1646afd..c026ffca 100644 --- a/docs/develop-guides/changelog.md +++ b/docs/develop-guides/changelog.md @@ -24,6 +24,7 @@ - 收敛 MCP 创建与编辑入口:前端移除整段配置文本入口和模式切换器,仅保留表单字段提交;后端 MCP 创建/更新请求拒绝额外配置字段,避免绕过表单约束。 - 调整内置 MCP 默认项:移除 `sequentialthinking` 的系统内置同步,启动同步时清理历史系统内置记录,保留用户手动创建的同名 MCP。 - 图片生成能力迁移为 Skill:Qwen-Image 从内置 Python 生成工具迁移到内置 Skill `image-gen`,模型调用与图片下载在 Agent 沙盒中完成,生成结果保存到 outputs 并通过 `present_artifacts` 展示,为多图片生成模型接入复用同一产物展示链路。 +- 优化前端头像加载兜底:用户与智能体头像优先展示已配置图片,加载失败后回退到基于 ID 的 DiceBear 默认头像;离线或默认头像不可达时显示名称前两个字和稳定背景色。 - 降低知识库路由与工具模块复杂度:示例问题生成迁移到知识库 utils,文件上传统一 100 MB 限制,URL 预处理入库路径与旧 `content_type=url` 行为收敛,并修复 uid、导出 MIME 与异常透传等路由问题。 - 重构智能体配置语义:用户可见的 `AgentConfig` 收敛为数据库持久化的一级 `Agent`,内置 Python Agent 改为智能体后端;新增 `/api/agent` 管理与运行接口,聊天、运行任务、恢复审批和文件预览均从线程绑定的 Agent 解析运行时上下文,前端只提交 `agent_id`,并在模型配置页新增“智能体”管理页签。 - 删除 Upload 与 LightRAG 图谱/知识库能力:知识库类型收敛为 Milvus 与 Dify,只保留 Milvus 知识库内图谱构建/展示/检索,移除独立 `/graph` 页面和默认上传图谱工具。 diff --git a/web/src/components/AccountSettingsComponent.vue b/web/src/components/AccountSettingsComponent.vue index 1760042c..806163e9 100644 --- a/web/src/components/AccountSettingsComponent.vue +++ b/web/src/components/AccountSettingsComponent.vue @@ -20,9 +20,17 @@ accept="image/*" >
- - - +
@@ -103,8 +111,9 @@ @@ -337,19 +327,10 @@ watch(() => [userStore.username, userStore.phoneNumber], syncProfileDraft, { imm flex: 0 0 auto; box-shadow: 0 2px 8px var(--shadow-2); - :deep(.ant-avatar) { + .account-avatar { width: 80px; height: 80px; border: 3px solid var(--gray-150); - background: var(--gray-50); - color: var(--gray-400); - display: flex; - align-items: center; - justify-content: center; - } - - :deep(.ant-avatar-image img) { - object-fit: cover; } &:hover .avatar-mask, diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue index e9a87df1..1ebbe5d4 100644 --- a/web/src/components/AgentChatComponent.vue +++ b/web/src/components/AgentChatComponent.vue @@ -400,13 +400,17 @@ :class="{ 'is-clickable': run.child_thread_id }" @click="run.child_thread_id && openSubagentThread(run)" > - -
{{ getSubagentRunName(run) }} @@ -445,6 +449,7 @@ :child-thread-id="subagentThreadModal.childThreadId" :subagent-name="activeSubagentThreadName" :subagent-avatar="activeSubagentThreadAvatar" + :subagent-default-avatar="activeSubagentThreadDefaultAvatar" />
@@ -500,6 +505,7 @@ import AgentArtifactsCard from '@/components/AgentArtifactsCard.vue' import AgentPanel from '@/components/AgentPanel.vue' import AttachmentTmpUploadModal from '@/components/AttachmentTmpUploadModal.vue' import SubagentThreadModal from '@/components/SubagentThreadModal.vue' +import FallbackAvatar from '@/components/common/FallbackAvatar.vue' import { enrichTaskToolCalls, parseToolCallArgs } from '@/components/ToolCallingResult/toolRegistry' import { getConversationDisplayItems } from '@/utils/messageGrouping' import { makeChildThreadId } from '@/utils/subagentThread' @@ -680,9 +686,12 @@ const getSubagentAgent = (run) => { const getSubagentIconSrc = (run) => { const agent = getSubagentAgent(run) - return agent?.icon || (run?.subagent_type ? generatePixelAvatar(run.subagent_type) : '') + return agent?.icon || '' } +const getSubagentDefaultIconSrc = (run) => + run?.subagent_type ? generatePixelAvatar(run.subagent_type) : '' + const getSubagentRunMeta = (run) => { const artifacts = Array.isArray(run?.artifacts) ? run.artifacts.length : 0 return artifacts ? `${artifacts} 个产物` : run?.id || '' @@ -902,13 +911,15 @@ const subagentThreadModal = reactive({ open: false, childThreadId: '', subagentName: '', - subagentAvatar: '' + subagentAvatar: '', + subagentDefaultAvatar: '' }) const openSubagentThread = (run) => { if (!run?.child_thread_id) return subagentThreadModal.childThreadId = String(run.child_thread_id) subagentThreadModal.subagentName = getSubagentRunName(run) subagentThreadModal.subagentAvatar = getSubagentIconSrc(run) + subagentThreadModal.subagentDefaultAvatar = getSubagentDefaultIconSrc(run) subagentThreadModal.open = true } const isStateSectionExpanded = (key) => !collapsedStateSections[key] @@ -1159,6 +1170,12 @@ const activeSubagentThreadAvatar = computed(() => ? getSubagentIconSrc(activeSubagentThreadRun.value) || subagentThreadModal.subagentAvatar : subagentThreadModal.subagentAvatar ) +const activeSubagentThreadDefaultAvatar = computed(() => + activeSubagentThreadRun.value + ? getSubagentDefaultIconSrc(activeSubagentThreadRun.value) || + subagentThreadModal.subagentDefaultAvatar + : subagentThreadModal.subagentDefaultAvatar +) // 首次运行的子智能体:前端按后端同样的哈希推算 child_thread_id,缓存到映射里供面板/轨迹定位。 watch( diff --git a/web/src/components/SubagentThreadModal.vue b/web/src/components/SubagentThreadModal.vue index 77594b1b..5a3d9af0 100644 --- a/web/src/components/SubagentThreadModal.vue +++ b/web/src/components/SubagentThreadModal.vue @@ -8,13 +8,17 @@ > @@ -31,6 +35,7 @@ import { computed, ref, watch } from 'vue' import { agentApi } from '@/apis' import { MessageProcessor } from '@/utils/messageProcessor' import ThreadMessageList from '@/components/ThreadMessageList.vue' +import FallbackAvatar from '@/components/common/FallbackAvatar.vue' const props = defineProps({ open: { @@ -48,6 +53,10 @@ const props = defineProps({ subagentAvatar: { type: String, default: '' + }, + subagentDefaultAvatar: { + type: String, + default: '' } }) diff --git a/web/src/components/UserInfoComponent.vue b/web/src/components/UserInfoComponent.vue index 2064fa34..aef5ec48 100644 --- a/web/src/components/UserInfoComponent.vue +++ b/web/src/components/UserInfoComponent.vue @@ -3,14 +3,17 @@