diff --git a/docs/agents/agents-config.md b/docs/agents/agents-config.md
index 78db7171..f5d26bef 100644
--- a/docs/agents/agents-config.md
+++ b/docs/agents/agents-config.md
@@ -258,13 +258,13 @@ config_json.context + runtime ids -> context_schema instance
## 5. `capabilities` 的作用
-`capabilities` 用于声明前端能力开关,控制 UI 组件显示,不等同于 Context。
+`capabilities` 用于声明前端可直接从 Agent 静态元数据判断的能力开关,控制上传入口、文件面板等固定 UI,不等同于 Context,也不适合表达运行中才会出现的状态。
示例:
```python
class MyAgent(BaseAgent):
- capabilities = ["file_upload", "files", "todo"]
+ capabilities = ["file_upload", "files"]
```
当前常见能力包括:
@@ -273,9 +273,10 @@ class MyAgent(BaseAgent):
| --- | --- |
| `file_upload` | 启用上传入口 |
| `files` | 启用文件面板 |
-| `todo` | 启用待办能力 |
-它解决的是“页面上显示什么”,而不是“运行时如何配置模型和工具”。
+像 todo 这类运行态信息,不建议再放进 `capabilities`。Yuxi 当前会直接从 LangGraph state 中提取 `agent_state.todos`,前端按运行时是否真的存在任务来决定是否展示待办入口与状态卡片。
+
+它解决的是“Agent 先天支持什么固定入口”,而不是“运行时当前产生了什么状态”。
## 6. 开发建议
diff --git a/web/src/assets/css/base.css b/web/src/assets/css/base.css
index 0769a6b1..7178a299 100644
--- a/web/src/assets/css/base.css
+++ b/web/src/assets/css/base.css
@@ -106,6 +106,34 @@
--bg-sider: var(--main-5);
--color-text: var(--c-black);
+
+ --light-98: rgba(255, 255, 255, 0.98);
+ --light-95: rgba(255, 255, 255, 0.95);
+ --light-90: rgba(255, 255, 255, 0.9);
+ --light-85: rgba(255, 255, 255, 0.85);
+ --light-80: rgba(255, 255, 255, 0.8);
+ --light-75: rgba(255, 255, 255, 0.75);
+ --light-70: rgba(255, 255, 255, 0.7);
+ --light-50: rgba(255, 255, 255, 0.5);
+ --light-25: rgba(255, 255, 255, 0.25);
+ --light-10: rgba(255, 255, 255, 0.1);
+ --light-5: rgba(255, 255, 255, 0.05);
+ --light-0: rgba(255, 255, 255, 0);
+
+ --dark-98: rgba(0, 0, 0, 0.98);
+ --dark-95: rgba(0, 0, 0, 0.95);
+ --dark-90: rgba(0, 0, 0, 0.9);
+ --dark-85: rgba(0, 0, 0, 0.85);
+ --dark-80: rgba(0, 0, 0, 0.8);
+ --dark-75: rgba(0, 0, 0, 0.75);
+ --dark-70: rgba(0, 0, 0, 0.7);
+ --dark-50: rgba(0, 0, 0, 0.5);
+ --dark-25: rgba(0, 0, 0, 0.25);
+ --dark-10: rgba(0, 0, 0, 0.1);
+ --dark-5: rgba(0, 0, 0, 0.05);
+ --dark-0: rgba(0, 0, 0, 0);
+
+
/* Shadow System - 阴影系统 */
--shadow-0: rgba(0, 0, 0, 0.02);
--shadow-1: rgba(0, 0, 0, 0.05);
diff --git a/web/src/assets/css/base.dark.css b/web/src/assets/css/base.dark.css
index 825c69b6..c9d94e8f 100644
--- a/web/src/assets/css/base.dark.css
+++ b/web/src/assets/css/base.dark.css
@@ -98,6 +98,33 @@
--bg-sider: #141414;
--color-text: #ffffff;
+
+ --dark-98: rgba(255, 255, 255, 0.98);
+ --dark-95: rgba(255, 255, 255, 0.95);
+ --dark-90: rgba(255, 255, 255, 0.9);
+ --dark-85: rgba(255, 255, 255, 0.85);
+ --dark-80: rgba(255, 255, 255, 0.8);
+ --dark-75: rgba(255, 255, 255, 0.75);
+ --dark-70: rgba(255, 255, 255, 0.7);
+ --dark-50: rgba(255, 255, 255, 0.5);
+ --dark-25: rgba(255, 255, 255, 0.25);
+ --dark-10: rgba(255, 255, 255, 0.1);
+ --dark-5: rgba(255, 255, 255, 0.05);
+ --dark-0: rgba(255, 255, 255, 0);
+
+ --light-98: rgba(0, 0, 0, 0.98);
+ --light-95: rgba(0, 0, 0, 0.95);
+ --light-90: rgba(0, 0, 0, 0.9);
+ --light-85: rgba(0, 0, 0, 0.85);
+ --light-80: rgba(0, 0, 0, 0.8);
+ --light-75: rgba(0, 0, 0, 0.75);
+ --light-70: rgba(0, 0, 0, 0.7);
+ --light-50: rgba(0, 0, 0, 0.5);
+ --light-25: rgba(0, 0, 0, 0.25);
+ --light-10: rgba(0, 0, 0, 0.1);
+ --light-5: rgba(0, 0, 0, 0.05);
+ --light-0: rgba(0, 0, 0, 0);
+
/* Ant Design 兼容变量 - 深色模式 */
--color-bg-container: #1f1f1f;
--color-bg-elevated: #262626;
diff --git a/web/src/components/AgentChatComponent.vue b/web/src/components/AgentChatComponent.vue
index 7e384c20..9dfcdd8a 100644
--- a/web/src/components/AgentChatComponent.vue
+++ b/web/src/components/AgentChatComponent.vue
@@ -167,6 +167,7 @@
:supports-file-upload="supportsFileUpload"
:is-panel-open="isAgentPanelOpen"
:has-active-thread="!!currentChatId"
+ :todos="currentTodos"
@send="handleSendOrStop"
@upload-attachment="handleAttachmentUpload"
@toggle-panel="toggleAgentPanel"
@@ -222,7 +223,6 @@
:agent-id="currentThread?.agent_id || currentAgentId"
:agent-config-id="selectedAgentConfigId"
:panel-ratio="panelRatio"
- :supports-todo="supportsTodo"
:is-expanded="isAgentPanelExpanded"
@refresh="handleAgentStateRefresh"
@close="toggleAgentPanel"
@@ -411,11 +411,6 @@ const supportsFileUpload = computed(() => {
const capabilities = currentAgent.value.capabilities || []
return capabilities.includes('file_upload')
})
-const supportsTodo = computed(() => {
- if (!currentAgent.value) return false
- const capabilities = currentAgent.value.capabilities || []
- return capabilities.includes('todo')
-})
const supportsFiles = computed(() => {
if (!currentAgent.value) return false
@@ -439,13 +434,15 @@ const currentArtifacts = computed(() => {
const artifacts = currentAgentState.value?.artifacts
return Array.isArray(artifacts) ? artifacts : []
})
+const currentTodos = computed(() => {
+ const todos = currentAgentState.value?.todos
+ return Array.isArray(todos) ? todos : []
+})
const hasAgentStateContent = computed(() => {
- const s = currentAgentState.value
- if (!s && currentThreadFiles.value.length === 0) return false
- const todoCount = Array.isArray(s?.todos) ? s.todos.length : 0
+ if (currentThreadFiles.value.length === 0) return false
const fileCount = currentThreadFiles.value.filter((item) => item?.is_dir !== true).length
- return todoCount > 0 || fileCount > 0
+ return fileCount > 0
})
// 监听 hasAgentStateContent 从 false → true 时,自动展开面板
@@ -936,7 +933,6 @@ const { handleAgentResponse, handleStreamChunk } = useAgentStreamHandler({
getThreadState,
processApprovalInStream,
currentAgentId,
- supportsTodo,
supportsFiles,
streamSmoother
})
diff --git a/web/src/components/AgentInputArea.vue b/web/src/components/AgentInputArea.vue
index e9320397..3b0c4d6a 100644
--- a/web/src/components/AgentInputArea.vue
+++ b/web/src/components/AgentInputArea.vue
@@ -31,21 +31,66 @@