Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<sub>Screenshot from v0.4.5 — predates the Digital Employee rename and the Skills section in the sidebar.</sub>
<sub>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.</sub>

## Core Features

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
3 changes: 0 additions & 3 deletions app/apps/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, any>;
Expand Down Expand Up @@ -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}
/>
</>
Expand Down
14 changes: 3 additions & 11 deletions app/apps/components/AgentMdEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -51,7 +46,6 @@ export default function AgentMdEditor({
appId,
ownerUserId,
platform,
promptId,
onChanged,
}: AgentMdEditorProps) {
const t = useTranslations("skills");
Expand All @@ -73,7 +67,6 @@ export default function AgentMdEditor({
const isWechat = platform === "Wechat";
const isLegacy = agentMd?.is_legacy !== false;
// 有旧提示词 = 真的在"升级";没有 = 从零"创建"
const hasLegacyPrompt = promptId != null;

// 后端内容加载/变化时回填(本地有未保存修改则不覆盖)
useEffect(() => {
Expand Down Expand Up @@ -145,8 +138,7 @@ export default function AgentMdEditor({
{/*
标题直接写「角色设定」,不再显示文件名 Agent.md,也不再挂状态徽章:
标题旁边写着「角色设定」、下面又挂一个写着「角色设定」的彩色 Badge,
是同一句话说两遍。isLegacy 的状态由下面那段说明文字承担
(legacyDesc / noAgentMdDesc 已经把处境讲清楚了)。
是同一句话说两遍。状态由下面那段说明文字承担(noAgentMdDesc)。
*/}
<CardTitle className="flex items-center gap-2">
<FileText className="h-5 w-5" />
Expand Down Expand Up @@ -179,7 +171,7 @@ export default function AgentMdEditor({
{isLegacy ? (
<div className="text-center py-6 space-y-3">
<p className="text-sm text-muted-foreground">
{hasLegacyPrompt ? t("legacyDesc") : t("noAgentMdDesc")}
{t("noAgentMdDesc")}
</p>
{canManage && (
<>
Expand All @@ -189,7 +181,7 @@ export default function AgentMdEditor({
) : (
<Sparkles className="h-4 w-4 mr-2" />
)}
{hasLegacyPrompt ? t("upgradeToAgentMd") : t("createAgentMd")}
{t("createAgentMd")}
</Button>
{isWechat && (
<p className="text-xs text-muted-foreground">{t("wechatUpgradeDisabled")}</p>
Expand Down
12 changes: 3 additions & 9 deletions app/apps/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<string, any>;
is_default?: boolean;
Expand All @@ -201,7 +199,6 @@ export default function AppsPage() {
platform: "Web",
avatar_url: null,
ai_model: "deepseek",
prompt_id: null,
dataset_ids: [],
email: "",
settings: {},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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: [
Expand Down Expand Up @@ -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 || {},
Expand Down
11 changes: 0 additions & 11 deletions app/components/AppSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
7 changes: 1 addition & 6 deletions app/components/DynamicTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const routeTitleKeys: { [key: string]: string } = {
"/graph": "knowledgeGraph",
"/process-management": "processManagement",
"/sop": "sopManagement",
"/prompts": "promptManagement",
"/organization": "organization",
"/user": "userManagement",
"/settings": "settings",
Expand All @@ -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() {
Expand Down Expand Up @@ -75,7 +70,7 @@ export default function DynamicTitle() {
<Badge variant="outline" className="text-xs hidden sm:inline-flex">
<Shield className="mr-1 h-3 w-3" />
<a href="/about" className="text-primary hover:underline">
v0.4.5
v0.5.0
</a>
</Badge>
</div>
Expand Down
Loading
Loading