From af5f5e6019fc91f407f47e7f4f6fa8e2d8af46f2 Mon Sep 17 00:00:00 2001 From: Jesse <15653378+squarezw@user.noreply.gitee.com> Date: Mon, 10 Aug 2026 10:56:37 +0800 Subject: [PATCH] docs: 0.5.0 README, and remove the prompt library from the front end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Removing the prompt library The prompt library had already stopped doing anything. `resolve_app_prompt_body` dropped the legacy `prompt_id` fallback on 2026-07-31, so a digital employee's system prompt comes from `agent_md` and nothing else. Checked before deleting: nine apps still carry a `prompt_id`, and all nine already have an `agent_md`. The chat runtime does not read the prompts table at all. So the menu entry was pointing at a feature that no longer had an effect, with a "being retired" notice attached. Gone now, along with the pages, the API proxy routes, the `prompts` i18n namespace, and the `prompt_id` field that was being threaded through app types and payloads. `/monitoring/prompts` is gone too — it was only ever a title mapping in `DynamicTitle`; the page itself never existed, so that entry pointed at a 404. `AgentMdEditor` no longer takes `promptId`. It only drove wording — "upgrade to Agent.md" versus "create Agent.md" — and with no prompt library there is nothing to upgrade from, so it always says create. Deliberately kept, since they only share the word "prompt": the workflow node's `systemPrompt` field, the dataset `promptType` setting, the crawler's prompt, and `/api/v1/prompt-variables`, which the skill editor uses. The backend `prompts` table and its endpoints are untouched — the public chat API still accepts an explicit `prompt_id`, and removing that is a separate decision made on the service side. ## README Switched to the new dashboard screenshot, which shows Digital Employees and Skills. The caption says plainly that the greyed-out Prompt entry and the version badge in the image predate this release — the image was taken before these changes, and a screenshot showing a menu item that no longer exists is exactly the kind of small wrongness that confuses a new reader. Rewrote the prompts section from "being retired" to "removed", and added the built-in skill-creator to the Skills section: it is the headline of 0.5.0 and the README did not mention it. The paragraph leads with what it does and ends with what it cannot do — approval stays human, and a draft's scripts are not executable until someone approves them. ## Checks 246 passed. `tsc` reports 134 errors against a 135 baseline — one fewer, since the deleted code carried one. `check:i18n` still fails, as it does on `main`: 3676 reported "missing keys" there versus 3592 here, almost all of them URL strings the scanner mistakes for keys. Pre-existing and unrelated. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 19 +- app/apps/[id]/page.tsx | 3 - app/apps/components/AgentMdEditor.tsx | 14 +- app/apps/page.tsx | 12 +- app/components/AppSidebar.tsx | 11 - app/components/DynamicTitle.tsx | 7 +- app/prompts/[id]/page.tsx | 260 ------------- app/prompts/new/page.tsx | 195 ---------- app/prompts/page.tsx | 394 -------------------- docs/assets/screenshot02.png | Bin 0 -> 572676 bytes messages/en/navigation.json | 7 +- messages/en/prompts.json | 65 ---- messages/zh-CN/navigation.json | 7 +- messages/zh-CN/prompts.json | 65 ---- pages/api/prompts/[id].ts | 166 --------- pages/api/prompts/[id]/associated-apps.ts | 46 --- pages/api/prompts/index.ts | 178 --------- pages/api/v1/apps/[id]/agent-md/generate.ts | 2 +- types/i18n.d.ts | 1 - types/workflow.ts | 1 - 20 files changed, 24 insertions(+), 1429 deletions(-) delete mode 100644 app/prompts/[id]/page.tsx delete mode 100644 app/prompts/new/page.tsx delete mode 100644 app/prompts/page.tsx create mode 100644 docs/assets/screenshot02.png delete mode 100644 messages/en/prompts.json delete mode 100644 messages/zh-CN/prompts.json delete mode 100644 pages/api/prompts/[id].ts delete mode 100644 pages/api/prompts/[id]/associated-apps.ts delete mode 100644 pages/api/prompts/index.ts diff --git a/README.md b/README.md index 8f581d6..f49c287 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ An enterprise AI agent platform (智能体中台) built with Next.js. It lets organizations build and operate AI agent applications on top of their own knowledge and business processes — from RAG-powered knowledge bases and intelligent Q&A to visual workflow orchestration, process management, and multi-tenant administration. -![RAgent screenshot](docs/assets/screenshot01.png) +![RAgent screenshot](docs/assets/screenshot02.png) -Screenshot from v0.4.5 — predates the Digital Employee rename and the Skills section in the sidebar. +Dashboard, showing the Digital Employees and Skills sections. The greyed-out Prompt entry +and the version badge predate v0.5.0, which removed the prompt library. ## Core Features @@ -35,6 +36,13 @@ filesystem at runtime — and the UI covers authoring, review, binding, and per- variables it needs via a `.env.example` asset; each user fills in their own values, injected per execution. Values are never returned by any endpoint, including to administrators, who see only which keys are set. +- **Skills can be written by talking.** A built-in skill-creator ships with the platform. Bind + it to a digital employee and you can ask for a skill in plain language instead of starting + from a blank editor. It drafts the body, writes scripts, configures the sandbox and submits + for review — but approval stays a human action, and a draft's scripts are not in the + executable set until someone approves them. The built-in skill itself cannot be edited or + deleted by anyone, since it is versioned with the code and any change would be overwritten + on the next release. > ⚠️ **Deployment requirement.** Skill *execution* needs the `ragent-service` process to be > able to run `docker`. If the backend itself runs in a container, that container needs the @@ -44,9 +52,10 @@ filesystem at runtime — and the UI covers authoring, review, binding, and per- ## Agent prompts A digital employee's system prompt lives in its **Agent.md**, edited on the employee's own -page. The standalone prompt library is being retired and its navigation entry is disabled; -existing prompts were copied into the corresponding Agent.md verbatim, and the original -`prompt_id` is kept as a rollback anchor. +page. That is the only place it lives. + +The standalone prompt library was removed in v0.5.0. Existing prompts had already been copied +into the corresponding Agent.md verbatim, and nothing reads the old records at runtime. ## Architecture diff --git a/app/apps/[id]/page.tsx b/app/apps/[id]/page.tsx index b7b0f98..5ad09ca 100644 --- a/app/apps/[id]/page.tsx +++ b/app/apps/[id]/page.tsx @@ -91,8 +91,6 @@ interface AppInfo { /** 头像 URL:内置头像静态路径或上传后的 OSS 读代理路径;空=按名称生成占位 */ avatar_url?: string | null; agent_md?: string | null; - /** legacy 提示词绑定;用来判断 Agent.md 区块该说「升级」还是「创建」 */ - prompt_id?: number | null; created_at: string; updated_at: string; settings?: Record; @@ -586,7 +584,6 @@ export default function AppDetailPage({ params }: { params: Promise<{ id: string appId={appId} ownerUserId={appInfo.user_id} platform={appInfo.platform} - promptId={appInfo.prompt_id} onChanged={loadAppInfo} /> diff --git a/app/apps/components/AgentMdEditor.tsx b/app/apps/components/AgentMdEditor.tsx index 2015817..b3990c5 100644 --- a/app/apps/components/AgentMdEditor.tsx +++ b/app/apps/components/AgentMdEditor.tsx @@ -31,11 +31,6 @@ interface AgentMdEditorProps { /** app 的创建者。后端的 agent-md 写入一直是 owner 或超管,UI 此前只放超管 */ ownerUserId?: number | null; platform: string; - /** - * 应用绑定的 legacy prompt。没有它就没有"升级"可言——文案要说「创建」, - * 否则用户看到「升级为 Agent.md」会以为有东西要迁移(2026-07-31 报的 bug 现场)。 - */ - promptId?: number | null; /** Agent.md 状态变化(升级 / 回退)后通知父组件刷新应用信息 */ onChanged?: () => void; } @@ -51,7 +46,6 @@ export default function AgentMdEditor({ appId, ownerUserId, platform, - promptId, onChanged, }: AgentMdEditorProps) { const t = useTranslations("skills"); @@ -73,7 +67,6 @@ export default function AgentMdEditor({ const isWechat = platform === "Wechat"; const isLegacy = agentMd?.is_legacy !== false; // 有旧提示词 = 真的在"升级";没有 = 从零"创建" - const hasLegacyPrompt = promptId != null; // 后端内容加载/变化时回填(本地有未保存修改则不覆盖) useEffect(() => { @@ -145,8 +138,7 @@ export default function AgentMdEditor({ {/* 标题直接写「角色设定」,不再显示文件名 Agent.md,也不再挂状态徽章: 标题旁边写着「角色设定」、下面又挂一个写着「角色设定」的彩色 Badge, - 是同一句话说两遍。isLegacy 的状态由下面那段说明文字承担 - (legacyDesc / noAgentMdDesc 已经把处境讲清楚了)。 + 是同一句话说两遍。状态由下面那段说明文字承担(noAgentMdDesc)。 */} @@ -179,7 +171,7 @@ export default function AgentMdEditor({ {isLegacy ? (

- {hasLegacyPrompt ? t("legacyDesc") : t("noAgentMdDesc")} + {t("noAgentMdDesc")}

{canManage && ( <> @@ -189,7 +181,7 @@ export default function AgentMdEditor({ ) : ( )} - {hasLegacyPrompt ? t("upgradeToAgentMd") : t("createAgentMd")} + {t("createAgentMd")} {isWechat && (

{t("wechatUpgradeDisabled")}

diff --git a/app/apps/page.tsx b/app/apps/page.tsx index 317a7ef..58c36a6 100644 --- a/app/apps/page.tsx +++ b/app/apps/page.tsx @@ -78,7 +78,6 @@ interface App { avatar_url?: string | null; user_id: number; ai_model: string; - prompt_id: number | null; agent_md?: string | null; dataset_ids: string[]; tool_count?: number; @@ -189,8 +188,7 @@ export default function AppsPage() { // 空串 = 用户主动清空(后端据此落 NULL);null = 本来就没设过 avatar_url: string | null; ai_model: string; - prompt_id: number | null; - dataset_ids: string[]; + dataset_ids: string[]; email?: string; settings: Record; is_default?: boolean; @@ -201,7 +199,6 @@ export default function AppsPage() { platform: "Web", avatar_url: null, ai_model: "deepseek", - prompt_id: null, dataset_ids: [], email: "", settings: {}, @@ -320,8 +317,7 @@ export default function AppsPage() { platform: "Web", avatar_url: null, ai_model: "deepseek", - prompt_id: null, - dataset_ids: [], + dataset_ids: [], email: "", settings: {}, is_default: false, @@ -349,8 +345,7 @@ export default function AppsPage() { app_type: "Chat" as const, platform: "Web" as const, ai_model: "deepseek", - prompt_id: null, - dataset_ids: ["quality_knowledge_base"], // 使用质量知识库 + dataset_ids: ["quality_knowledge_base"], // 使用质量知识库 settings: { workflow: { nodes: [ @@ -465,7 +460,6 @@ export default function AppsPage() { platform: app.platform, avatar_url: app.avatar_url ?? null, ai_model: app.ai_model, - prompt_id: app.prompt_id, dataset_ids: datasetIds, email: app.email || "", settings: app.settings || {}, diff --git a/app/components/AppSidebar.tsx b/app/components/AppSidebar.tsx index bb56491..ec1be3e 100644 --- a/app/components/AppSidebar.tsx +++ b/app/components/AppSidebar.tsx @@ -136,17 +136,6 @@ export default function AppSidebar() { visible: true, items: [ { title: t("chatSessions"), icon: MessageSquareMore, path: "/chat-sessions" }, - { - // 提示词管理即将下线:应用的提示词真源已迁到 Agent.md(apps.agent_md), - // chat 与企微两条链都优先读它(app/utils/app_prompt.resolve_app_prompt_body)。 - // 入口先置灰而不是直接删——`prompt_id` 仍保留作回滚锚点,真删要等确认没有 - // 应用还只靠它。 - title: t("promptManagement"), - icon: MessageSquare, - path: "/prompts", - visible: isSuperAdmin || isTenantAdmin, - deprecated: t("promptManagementDeprecated"), - }, { // P5 开放自建:普通用户也可创建自己的 Skill(草稿走提交审核) title: t("skillsManagement"), diff --git a/app/components/DynamicTitle.tsx b/app/components/DynamicTitle.tsx index 34d5347..287d7f3 100644 --- a/app/components/DynamicTitle.tsx +++ b/app/components/DynamicTitle.tsx @@ -13,7 +13,6 @@ const routeTitleKeys: { [key: string]: string } = { "/graph": "knowledgeGraph", "/process-management": "processManagement", "/sop": "sopManagement", - "/prompts": "promptManagement", "/organization": "organization", "/user": "userManagement", "/settings": "settings", @@ -23,14 +22,10 @@ const routeTitleKeys: { [key: string]: string } = { // 子路由标题映射 const subRouteTitleKeys: { [key: string]: string } = { - "/prompts/new": "newPrompt", - "/prompts/": "promptDetail", - "/monitoring/prompts": "promptMonitoring", }; // 动态路由模式匹配 const dynamicRoutePatterns: { pattern: RegExp; titleKey: string }[] = [ - { pattern: /^\/prompts\/[^/]+$/, titleKey: "promptDetail" }, ]; export default function DynamicTitle() { @@ -75,7 +70,7 @@ export default function DynamicTitle() { - v0.4.5 + v0.5.0
diff --git a/app/prompts/[id]/page.tsx b/app/prompts/[id]/page.tsx deleted file mode 100644 index b0a2608..0000000 --- a/app/prompts/[id]/page.tsx +++ /dev/null @@ -1,260 +0,0 @@ -"use client"; - -import { useState, useEffect } from "react"; -import { useRouter, useParams } from "next/navigation"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Checkbox } from "@/components/ui/checkbox"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { Badge } from "@/components/ui/badge"; -import { Separator } from "@/components/ui/separator"; -import axios from "@/lib/axios"; -import { useCurrentUser } from "@/hooks/useCurrentUser"; -import { toast } from "sonner"; -import { useTranslations } from "next-intl"; - -interface Prompt { - id: number; - role: string; - content: string; - visibility: "private" | "dept" | "tenant" | "public"; - is_default: boolean; - is_active: boolean; - user_id: number; - created_at: string; - updated_at: string; -} - -export default function EditPromptPage() { - const router = useRouter(); - const params = useParams(); - const promptId = params?.id as string; - const { user, loading: userLoading } = useCurrentUser(); - const t = useTranslations("prompts"); - const tc = useTranslations("common"); - - const [loading, setLoading] = useState(true); - const [saving, setSaving] = useState(false); - const [prompt, setPrompt] = useState(null); - const [formData, setFormData] = useState({ - role: "", - content: "", - visibility: "dept" as "private" | "dept" | "tenant" | "public", - is_default: false, - is_active: true, - }); - - useEffect(() => { - if (!user) return; - fetchPrompt(); - }, [user, promptId]); - - const fetchPrompt = async () => { - try { - setLoading(true); - const response = await axios.get(`/api/prompts`); - const prompts = response.data; - const currentPrompt = prompts.find((p: Prompt) => p.id.toString() === promptId); - - if (!currentPrompt) { - toast.error(t("promptNotFound")); - router.push("/prompts"); - return; - } - - // 检查权限:后端API会进行权限验证,这里不需要重复检查 - setPrompt(currentPrompt); - setFormData({ - role: currentPrompt.role, - content: currentPrompt.content, - visibility: currentPrompt.visibility, - is_default: currentPrompt.is_default, - is_active: currentPrompt.is_active, - }); - } catch (error: any) { - console.error("获取提示词失败:", error); - if (error.response?.status === 403) { - toast.error(t("noPermission")); - router.push("/prompts"); - } else { - toast.error(t("fetchFailed")); - router.push("/prompts"); - } - } finally { - setLoading(false); - } - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - if (!formData.role.trim()) { - alert(t("roleRequired")); - return; - } - - if (!formData.content.trim()) { - alert(t("contentRequired")); - return; - } - - try { - setSaving(true); - await axios.put(`/api/prompts/${promptId}`, formData); - toast.success(t("saveSuccess")); - router.push("/prompts"); - } catch (error: any) { - console.error("保存失败:", error); - if (error.response?.status === 403) { - toast.error(t("noEditPermission")); - router.push("/prompts"); - } else { - toast.error(error.response?.data?.error || t("saveFailed")); - } - } finally { - setSaving(false); - } - }; - - const handleCancel = () => { - router.push("/prompts"); - }; - - // 显示加载状态 - if (loading) { - return ( -
-
{tc("loading")}
-
- ); - } - - if (!user) { - return ( -
-
{t("cannotLoadUser")}
-
- ); - } - - if (!prompt) { - return ( -
-
{t("promptNotFound")}
-
- ); - } - - return ( -
-
-
- - -
-
- - - - {t("promptInfo")} - - -
-
-
- - setFormData({ ...formData, role: e.target.value })} - placeholder={t("roleNamePlaceholder")} - required - /> -
- -
- - -
-
- -
- -