From 08deda5b3f21eb1ebf1dd7c17aab5ae848ad7442 Mon Sep 17 00:00:00 2001 From: yu <2799341137@qq.com> Date: Wed, 5 Aug 2026 02:45:41 +0800 Subject: [PATCH] feat(web): add local Codex Skill management and invocation UI --- CHANGELOG.md | 4 + docs/content/docs/progress/pending-test.mdx | 5 +- .../components/agent/agent-chat-composer.tsx | 170 ++++++---- .../components/agent/agent-chat-message.tsx | 2 +- web/src/components/agent/agent-panel-tabs.tsx | 20 +- .../components/agent/agent-skill-picker.tsx | 85 +++++ .../components/agent/agent-skills-view.tsx | 295 ++++++++++++++++++ .../components/agent/local-agent-panel.tsx | 61 +++- .../api/canvas-agent.ts} | 54 ++++ web/src/stores/use-agent-skill-store.ts | 85 +++++ web/src/stores/use-agent-store.ts | 2 +- 11 files changed, 695 insertions(+), 88 deletions(-) create mode 100644 web/src/components/agent/agent-skill-picker.tsx create mode 100644 web/src/components/agent/agent-skills-view.tsx rename web/src/{components/agent/agent-api.ts => services/api/canvas-agent.ts} (53%) create mode 100644 web/src/stores/use-agent-skill-store.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c20fb06..27b2ed4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased ++ [新增] Agent 支持查看、创建、编辑、删除、启停和显式调用本地 Codex Skill,并同步多标签页变更。 ++ [调整] Agent 面板连接状态、内容标签和新对话统一排版,窄面板仅隐藏文字并保留图标与数量。 ++ [优化] Agent 输入区控件随面板宽度在图标与图标加文字之间自适应。 + ## v0.13.0 - 2026-08-03 + [优化] Agent 进入空白对话或点击新对话后后台预热 Codex 与 MCP。 diff --git a/docs/content/docs/progress/pending-test.mdx b/docs/content/docs/progress/pending-test.mdx index 52a587e..064acaf 100644 --- a/docs/content/docs/progress/pending-test.mdx +++ b/docs/content/docs/progress/pending-test.mdx @@ -13,7 +13,10 @@ description: 当前版本已实现但仍需人工验证的变更项 - Agent 首次发送响应:在空白新对话中输入内容并按回车后,输入框应立即清空、用户消息应立即出现在对话中,再显示「正在思考」;线程创建或发送失败时,原输入和附件应恢复;任务运行期间输入的新草稿不应在请求成功后被清空。 - Agent 动态工具信息:执行内置生图、查看图片、命令、文件修改或其他动态工具时,卡片标题应显示具体工具名称;执行失败时正文应显示真实错误原因,刷新并恢复历史对话后仍应保持一致,不再统一显示「工具操作已完成」。 - Agent 画布生图:重启 Canvas Agent 后,其自动生成的工作区 `AGENTS.md` 应同步为最新版指令(用户自行编写的其他 `AGENTS.md` 不应被覆盖);输入“生成一张图片”时应调用 `canvas_generate_image`,通过当前画布节点创建并运行生成流程;只有明确输入“使用 Codex 内置生图/ImageGen 技能生成”时才允许调用内置能力,Codex App Server 返回的 `imageGeneration` 结果应显示在对话中并作为保持原比例的图片节点添加到当前画布;Agent 不应在没有生成结果时提前声称“已生成”。 -- Agent 顶部栏:标题只显示垂直居中的「Agent」,连接、对话、历史、日志、新对话和收起操作应位于同一行;面板较窄时标签仍可横向滚动且操作不应错位。 +- Agent 顶部栏:在对话、历史和日志之间新增「技能」标签并显示已加载数量;连接状态应位于左侧 Agent 标题旁,并与右侧新对话使用相同规格的文字按钮,只有内容标签显示选中线;标签图标始终显示,窄面板仅隐藏文字并保留小号数量,宽面板显示图标和文字,拖动宽度时不应换行、横向滚动或错位。 +- Agent 输入框窄屏布局:底部上传、Skill、确认模式、权限模式、模型和思考程度控件在窄面板下应只显示图标,宽面板下恢复文字;所有纯图标操作悬停时应使用统一样式显示名称或当前状态,任意宽度都不出现横向溢出。 +- Agent 本地 Skill 管理:连接 Canvas Agent 后进入「技能」,应能读取当前 Codex 工作空间发现的项目、个人、系统和管理员 Skill,并支持搜索、按范围筛选、刷新及启停;未能加载的 Skill 应通过可点击、可滚动的详情查看原因;画布在站点工作空间 `.agents/skills` 下创建的 Skill 应可新建、编辑和删除,其他来源只读且不得被画布改写;编辑期间文件被其他窗口修改时应拒绝覆盖,清空显示名称、短说明和默认提示词后旧值应被删除,同时保留图标、品牌色等未由当前界面管理的元数据;多个标签页同时连接时,任一页面的 Skill 变更应自动同步,断开或切换 Agent 时旧请求不得重新写回列表或弹出编辑器。 +- Agent Skill 调用:在技能页点击「使用」或在输入框左下方选择 Skill 后,输入框上方应显示可移除标签;发送任务时应通过 Codex 原生结构化 Skill 输入执行,而不是只把名称拼进普通提示词,发送成功后清除选择,失败时保留;新建对话、断开连接、Skill 被停用或删除时也应清除失效选择,发送前、任务完成后和刷新历史后的用户消息文字应保持一致。 - Agent Markdown 样式:右侧 Agent 回复中的代码块应为横向占满消息区域、无语言标题和无双层边框的紧凑代码条,单行内容不应保留纵向大面积空白,复制操作仅在悬停时弱化显示;行内代码、链接在浅色和深色主题下应清晰;点击外部链接后应显示中文紧凑确认弹窗,长路径能够正常换行且复制、继续打开和关闭操作可用;点击 `/Users/`、`/home/` 等本地绝对文件路径时应改为提示在系统文件管理器中定位,支持复制路径,且浏览器地址不应跳转为 localhost 文件路径。 - Agent 工具确认模式:右侧面板标题栏不应再显示「工具确认」开关;对话输入框左下方应显示确认模式选择,默认选中「自动确认」,画布写入工具应直接执行;切换为「手动确认」后,画布写入工具应在对话中展示等待确认卡片,并支持批准或拒绝。 - Canvas Agent Codex 升级:启动 Canvas Agent 后应输出 Canvas Agent、内置 Codex 和本机 Codex 版本,实际运行的内置 Codex 应为 0.146.0;内置与本机版本不一致、未安装本机 Codex,或 npm 存在更新版本时应显示对应升级提醒,npm 检查失败不应阻止服务启动;Agent 应能正常连接 Codex、创建或恢复会话、发送消息并调用画布工具,运行中停止任务应只中断当前 turn,随后无需重启 Agent 即可继续发送新任务。 diff --git a/web/src/components/agent/agent-chat-composer.tsx b/web/src/components/agent/agent-chat-composer.tsx index 485da4a..51d8682 100644 --- a/web/src/components/agent/agent-chat-composer.tsx +++ b/web/src/components/agent/agent-chat-composer.tsx @@ -1,12 +1,14 @@ -import { useRef, type ReactNode } from "react"; +import { useRef, useState, type ReactNode } from "react"; import { Button, Dropdown, Tooltip } from "antd"; -import { ArrowUp, Check, ChevronUp, Cpu, Hand, ImagePlus, LoaderCircle, RefreshCw, ShieldAlert, ShieldCheck, ShieldOff, Square, X } from "lucide-react"; +import { ArrowUp, Check, ChevronUp, Cpu, Gauge, Hand, ImagePlus, LoaderCircle, RefreshCw, ShieldAlert, ShieldCheck, ShieldOff, Square, X } from "lucide-react"; import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select"; import { canvasThemes } from "@/lib/canvas-theme"; import { isPlainEnterKey } from "@/lib/keyboard-event"; +import { useAgentSkillStore } from "@/stores/use-agent-skill-store"; import type { AgentModel, AgentPermissionMode, AgentReasoningEffort } from "@/stores/use-agent-store"; import type { AgentChatAttachment } from "./agent-chat-message"; +import { AgentSkillPicker } from "./agent-skill-picker"; export function AgentChatComposer({ prompt, @@ -54,6 +56,8 @@ export function AgentChatComposer({ left?: ReactNode; }) { const fileInputRef = useRef(null); + const selectedSkill = useAgentSkillStore((state) => state.selectedSkill); + const clearSkillSelection = useAgentSkillStore((state) => state.clearSelection); const canSubmit = !disabled && !sending && Boolean(prompt.trim() || attachments.length); return (
event.stopPropagation()}> @@ -72,6 +76,16 @@ export function AgentChatComposer({ ))}
) : null} + {selectedSkill ? ( +
+ + {selectedSkill.interface?.displayName || selectedSkill.name} + + +
+ ) : null}