diff --git a/frontend/src/content/en/application/agents-and-threads.mdx b/frontend/src/content/en/application/agents-and-threads.mdx index 3bf3a2baf..51aecd860 100644 --- a/frontend/src/content/en/application/agents-and-threads.mdx +++ b/frontend/src/content/en/application/agents-and-threads.mdx @@ -19,7 +19,7 @@ The default agent is the Lead Agent with no custom configuration. It loads all g Custom agents are named variants of the Lead Agent. Each one can have: -- a **display name** and an auto-derived ASCII slug (the `name` used internally) +- a unique ASCII **name** used by the API, routes, and storage - a specific **model** to use by default - a restricted set of **skills** (or all globally enabled skills if unspecified) - a restricted set of **tool groups** @@ -30,18 +30,21 @@ Custom agents are created and managed through: - **The App UI**: open the Agents section in the settings panel. - **The Gateway API**: `POST /api/agents` with the agent definition. -The slug (`name`) is automatically derived from the `display_name` and must be unique. The system checks for conflicts and appends a suffix if needed (`/api/agents/check`). +Both paths require `agents_api.enabled: true` in `config.yaml`. The management API is disabled by default and should be exposed only within a trusted boundary. -Agent configuration is stored in `agents/{name}/config.yaml` relative to the backend directory. +The `name` must match `^[A-Za-z0-9-]+$` and be unique per user. The backend stores it in lowercase. Use `/api/agents/check?name={name}` to validate a name and check whether it is available before creating the agent. + +With the default `agent_storage.backend: file`, agent configuration is stored per user at `{base_dir}/users/{user_id}/agents/{name}/config.yaml`, where `{base_dir}` is `DEER_FLOW_HOME` (default: `backend/.deer-flow`). The older `{base_dir}/agents/{name}/` layout remains a read-only fallback for installations that have not yet run `backend/scripts/migrate_user_isolation.py`. With `agent_storage.backend: db`, definitions are stored in the shared SQL database instead; it requires `database.backend: sqlite` or `database.backend: postgres`. Use `backend/scripts/migrate_agents_to_db.py` to migrate existing file-backed definitions. + +For the file backend, you can edit these files directly; changes are picked up on the agent's next invocation, with no restart needed. ### Restricting agent capabilities To restrict a custom agent to specific skills: ```yaml -# agents/my-researcher/config.yaml +# {base_dir}/users/{user_id}/agents/my-researcher/config.yaml name: my-researcher -display_name: My Researcher skills: - deep-research - academic-paper-review diff --git a/frontend/src/content/en/harness/lead-agent.mdx b/frontend/src/content/en/harness/lead-agent.mdx index 3da01bc4d..583c56090 100644 --- a/frontend/src/content/en/harness/lead-agent.mdx +++ b/frontend/src/content/en/harness/lead-agent.mdx @@ -132,13 +132,13 @@ Plan mode is appropriate for complex, multi-step tasks where showing incremental The same Lead Agent runtime powers both the default agent and any custom agents you create. A custom agent differs only in: -- its **name** (ASCII slug, auto-derived from `display_name`), +- its unique ASCII **name**, used by the API, routes, and storage, - its **system prompt** or agent-specific instructions, - which **skills** it has access to, - which **tool groups** it can use, and - which **model** it defaults to. -Custom agents are created through the DeerFlow App UI or via the `/api/agents` endpoint. Their configuration is stored in `agents/{name}/config.yaml` relative to the backend directory. +Custom agents are created through the DeerFlow App UI or via the `/api/agents` endpoint. Both paths require `agents_api.enabled: true` in `config.yaml`; the management API is disabled by default. With the default `agent_storage.backend: file`, configuration is stored per user at `{base_dir}/users/{user_id}/agents/{name}/config.yaml`, where `{base_dir}` is `DEER_FLOW_HOME` (default: `backend/.deer-flow`). With `agent_storage.backend: db`, definitions are stored in the shared SQL database instead; it requires `database.backend: sqlite` or `database.backend: postgres`. Use `backend/scripts/migrate_agents_to_db.py` to migrate existing file-backed definitions. When a custom agent is selected in a thread, the Lead Agent loads that agent's diff --git a/frontend/src/content/zh/application/agents-and-threads.mdx b/frontend/src/content/zh/application/agents-and-threads.mdx index df3134657..ea7b7370a 100644 --- a/frontend/src/content/zh/application/agents-and-threads.mdx +++ b/frontend/src/content/zh/application/agents-and-threads.mdx @@ -23,6 +23,8 @@ DeerFlow 允许你创建多个具有不同专业领域的自定义 Agent。每 ### 创建自定义 Agent +以下两种方式都要求在 `config.yaml` 中设置 `agents_api.enabled: true`。管理 API 默认关闭,并且只应在可信边界内开放。 + #### 通过界面 @@ -39,7 +41,7 @@ DeerFlow 允许你创建多个具有不同专业领域的自定义 Agent。每 curl -X POST http://localhost:8001/api/agents \ -H "Content-Type: application/json" \ -d '{ - "display_name": "数据分析师", + "name": "data-analyst", "description": "专业的数据分析和可视化", "skills": ["data-analysis", "chart-visualization"] }' @@ -47,18 +49,17 @@ curl -X POST http://localhost:8001/api/agents \ -### Agent 名称和 Slug +### Agent 名称 -创建 Agent 时,`display_name` 对用户显示,系统内部使用自动派生的 ASCII `slug`(`name` 字段)来标识 Agent。 +创建 Agent 时,需要提供在每位用户范围内唯一的 ASCII `name`。该名称用于 API、路由和文件路径,必须匹配 `^[A-Za-z0-9-]+$`,后端会以小写形式存储它。 -- `display_name`:对用户显示的任意字符串(例如 "数据分析师") -- `name`(slug):用于 API 和文件路径的 ASCII 标识符(例如 `data-analyst`) - -如果派生的 slug 与现有 Agent 冲突,`/api/agents/check` 端点会建议一个唯一的替代名称。 +创建 Agent 前,可以调用 `/api/agents/check?name={name}` 验证名称并检查它是否可用。 ### Agent 存储 -自定义 Agent 配置存储在 `backend/agents/{name}/config.yaml` 中。你可以直接编辑这些文件——更改在下次 Agent 调用时自动加载。 +使用默认的 `agent_storage.backend: file` 时,自定义 Agent 配置按用户存储在 `{base_dir}/users/{user_id}/agents/{name}/config.yaml` 中,其中 `{base_dir}` 是 `DEER_FLOW_HOME`(默认值为 `backend/.deer-flow`)。旧的 `{base_dir}/agents/{name}/` 布局仅作为尚未执行 `backend/scripts/migrate_user_isolation.py` 的安装的只读回退路径。使用 `agent_storage.backend: db` 时,定义会改为存储在共享 SQL 数据库中;它要求 `database.backend: sqlite` 或 `database.backend: postgres`。使用 `backend/scripts/migrate_agents_to_db.py` 迁移已有的文件后端定义。 + +使用文件后端时,你可以直接编辑这些文件;更改会在下一次 Agent 调用时自动加载,无需重启。 ## 线程生命周期 diff --git a/frontend/src/content/zh/harness/lead-agent.mdx b/frontend/src/content/zh/harness/lead-agent.mdx index 3a3c8ce28..5decd5f1a 100644 --- a/frontend/src/content/zh/harness/lead-agent.mdx +++ b/frontend/src/content/zh/harness/lead-agent.mdx @@ -115,13 +115,13 @@ models: 相同的 Lead Agent 运行时同时为默认 Agent 和你创建的任何自定义 Agent 提供服务。自定义 Agent 的区别仅在于: -- 其**名称**(ASCII slug,从 `display_name` 自动派生) +- 其唯一的 ASCII **名称**(用于 API、路由和存储) - 其**系统提示**或 Agent 特定指令 - 它有权访问的**技能** - 它可以使用的**工具组** - 它默认使用的**模型** -自定义 Agent 通过 DeerFlow 应用界面或 `/api/agents` 端点创建。其配置存储在后端目录的 `agents/{name}/config.yaml` 中。 +自定义 Agent 通过 DeerFlow 应用界面或 `/api/agents` 端点创建。这两种方式都要求在 `config.yaml` 中设置 `agents_api.enabled: true`;管理 API 默认关闭。使用默认的 `agent_storage.backend: file` 时,配置按用户存储在 `{base_dir}/users/{user_id}/agents/{name}/config.yaml` 中,其中 `{base_dir}` 是 `DEER_FLOW_HOME`(默认值为 `backend/.deer-flow`)。使用 `agent_storage.backend: db` 时,定义会改为存储在共享 SQL 数据库中;它要求 `database.backend: sqlite` 或 `database.backend: postgres`。使用 `backend/scripts/migrate_agents_to_db.py` 迁移已有的文件后端定义。 当在线程中选择自定义 Agent 时,Lead Agent 在运行时加载该 Agent 的配置。为特定 diff --git a/frontend/tests/unit/content/docs-links.test.ts b/frontend/tests/unit/content/docs-links.test.ts index e88b16381..19672faac 100644 --- a/frontend/tests/unit/content/docs-links.test.ts +++ b/frontend/tests/unit/content/docs-links.test.ts @@ -86,4 +86,53 @@ describe("documentation content links", () => { expect(brokenLinks).toEqual([]); }); + + it("documents the custom-agent create request naming contract", () => { + const customAgentApiDocs = DOC_LANGUAGES.map((lang) => + readFileSync( + join(CONTENT_ROOT, lang, "application/agents-and-threads.mdx"), + "utf8", + ), + ); + const customAgentDocs = [ + ...customAgentApiDocs, + ...DOC_LANGUAGES.map((lang) => + readFileSync( + join(CONTENT_ROOT, lang, "harness/lead-agent.mdx"), + "utf8", + ), + ), + ]; + + for (const source of customAgentDocs) { + expect(source).toContain("agents_api.enabled"); + expect(source).toContain("agent_storage.backend: file"); + expect(source).toContain("agent_storage.backend: db"); + expect(source).toContain("database.backend: sqlite"); + expect(source).toContain("database.backend: postgres"); + expect(source).toContain("backend/scripts/migrate_agents_to_db.py"); + expect(source).toContain("users/{user_id}/agents/{name}/config.yaml"); + expect(source).not.toContain("display_name"); + } + + for (const source of customAgentApiDocs) { + expect(source).toContain("^[A-Za-z0-9-]+$"); + expect(source).toContain("backend/scripts/migrate_user_isolation.py"); + } + + const chineseApiGuide = readFileSync( + join(CONTENT_ROOT, "zh/application/agents-and-threads.mdx"), + "utf8", + ); + expect(chineseApiGuide).toContain('"name": "data-analyst"'); + expect(chineseApiGuide).toContain("下一次 Agent 调用时自动加载,无需重启"); + + const englishApiGuide = readFileSync( + join(CONTENT_ROOT, "en/application/agents-and-threads.mdx"), + "utf8", + ); + expect(englishApiGuide).toContain( + "changes are picked up on the agent's next invocation", + ); + }); });