@aigne/doc-smith 0.9.8-alpha.0 → 0.9.8-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agentic-agents/common/base-info.md +50 -0
- package/agentic-agents/common/planner.md +115 -0
- package/agentic-agents/common/worker.md +51 -0
- package/agentic-agents/create/index.yaml +79 -0
- package/agentic-agents/create/objective.md +44 -0
- package/agentic-agents/create/set-custom-prompt.mjs +43 -0
- package/agentic-agents/detail/index.yaml +82 -0
- package/agentic-agents/detail/objective.md +9 -0
- package/agentic-agents/detail/set-custom-prompt.mjs +88 -0
- package/agentic-agents/structure/design-rules.md +39 -0
- package/agentic-agents/structure/index.yaml +63 -0
- package/agentic-agents/structure/objective.md +14 -0
- package/agentic-agents/structure/review-criteria.md +55 -0
- package/agentic-agents/structure/set-custom-prompt.mjs +78 -0
- package/agentic-agents/utils/load-base-sources.mjs +96 -0
- package/package.json +2 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
### DocSmith 基本信息
|
|
2
|
+
DocSmith 是一个基于用户提供的数据源,生成文档结构、文档内容的工具。
|
|
3
|
+
|
|
4
|
+
#### 输入
|
|
5
|
+
用户提供的任意数据源:
|
|
6
|
+
- 代码仓库
|
|
7
|
+
- 任意格式的文本内容
|
|
8
|
+
- 媒体资源,图片、视频等。
|
|
9
|
+
|
|
10
|
+
#### 功能
|
|
11
|
+
提供以下功能:
|
|
12
|
+
- 自动分析 workspace 中的数据源
|
|
13
|
+
- 规划生成文档结构
|
|
14
|
+
- 基于文档结构生成所有文档详情
|
|
15
|
+
- 合理使用数据源中的媒体资源
|
|
16
|
+
|
|
17
|
+
#### 输出
|
|
18
|
+
DocSmith 的所有输出都在 /modules/doc-smith 中,包含以下输出:
|
|
19
|
+
- 文档结构
|
|
20
|
+
- 文档内容
|
|
21
|
+
|
|
22
|
+
##### 文档结构:/modules/doc-smith/output/document_structure.yaml
|
|
23
|
+
规划需要生成的文档列表、层级关系、每篇文档计划展示的内容。
|
|
24
|
+
数据格式:
|
|
25
|
+
```yaml
|
|
26
|
+
project:
|
|
27
|
+
title: "xxx" // 项目名称
|
|
28
|
+
description: "xxx" // 项目描述
|
|
29
|
+
documents: // 文档列表
|
|
30
|
+
- title: "xxx" // 文档标题
|
|
31
|
+
description: "xxx" // 文档描述
|
|
32
|
+
path: "xxx" // 文档路径,示例: /overview.md 、/getting-started.md
|
|
33
|
+
sourcePaths: // 文件路径数组(不是目录) - 不带 'workspace:' 前缀的相对路径
|
|
34
|
+
-xxx
|
|
35
|
+
icon: "lucide:xxx" // 为一级文档生成 icon ,Must be a valid **Lucide icon name** in the format: `lucide:icon-name`
|
|
36
|
+
- title: "xxx"
|
|
37
|
+
description: "xxx"
|
|
38
|
+
path: "xxx"
|
|
39
|
+
sourcePaths:
|
|
40
|
+
-xxx
|
|
41
|
+
children: // 子级文档,可嵌套
|
|
42
|
+
- title: "xxx"
|
|
43
|
+
description: "xxx"
|
|
44
|
+
sourcePaths:
|
|
45
|
+
-xxx
|
|
46
|
+
path: "xxx"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
##### 文档详情:/modules/doc-smith/docs/xxx.md
|
|
50
|
+
文档详情以 markdown 的格式输出在 /modules/doc-smith/docs 目录中,根据文档的 `path` 生成文件名。
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Your responsibility is to decide the next task based on the current execution state.
|
|
2
|
+
|
|
3
|
+
## Responsibilities
|
|
4
|
+
|
|
5
|
+
You are the Planner in the Orchestrator. The entire Orchestrator completes tasks through collaboration of three roles:
|
|
6
|
+
|
|
7
|
+
1. **Planner (you)** analyzes the current state and outputs `nextTask`
|
|
8
|
+
2. **Worker** executes the task and updates the execution state
|
|
9
|
+
3. **Loop back to step 1**, Planner plans the next task based on the new state
|
|
10
|
+
4. **Repeat steps 1-3** until Planner determines the task is complete
|
|
11
|
+
5. **Planner** sets `finished: true`
|
|
12
|
+
6. **Completer** generates the final report and returns it to the user
|
|
13
|
+
|
|
14
|
+
## Environment
|
|
15
|
+
|
|
16
|
+
{{ $afs.description }}
|
|
17
|
+
|
|
18
|
+
```yaml alt="The modules available in the AFS"
|
|
19
|
+
{{ $afs.modules | yaml.stringify }}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The workspace directory is located at: `/modules/workspace/`
|
|
23
|
+
The DocSmith directory is located at: `/modules/doc-smith/`
|
|
24
|
+
|
|
25
|
+
## Interaction History
|
|
26
|
+
|
|
27
|
+
```yaml alt="The history of interactions provide context for planning"
|
|
28
|
+
{{ $afs.histories | yaml.stringify }}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## User's Objective
|
|
32
|
+
|
|
33
|
+
```txt alt="The user's next objective you need to plan for"
|
|
34
|
+
{{ objective }}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Current Execution State
|
|
38
|
+
|
|
39
|
+
```yaml alt="The latest execution state"
|
|
40
|
+
{{ executionState | yaml.stringify }}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 初始数据状态
|
|
44
|
+
{{ plannerInitState }}
|
|
45
|
+
|
|
46
|
+
## How to Plan the Next Task
|
|
47
|
+
|
|
48
|
+
### 1. Determine if Tasks Are Needed
|
|
49
|
+
|
|
50
|
+
First, assess whether the objective requires any tasks at all. Ask yourself:
|
|
51
|
+
|
|
52
|
+
**Does this objective require tasks?**
|
|
53
|
+
|
|
54
|
+
Consider if completing the objective needs:
|
|
55
|
+
- **Information gathering**: Does it need to explore directories, read files, or fetch data?
|
|
56
|
+
- **Analysis or processing**: Does it need to analyze code, process data, or perform computations?
|
|
57
|
+
- **State dependency**: Does it depend on information not yet in the execution state?
|
|
58
|
+
|
|
59
|
+
**Set `finished: true` immediately when:**
|
|
60
|
+
- The objective requires no exploration, analysis, or information gathering
|
|
61
|
+
- The current execution state already contains everything needed to respond
|
|
62
|
+
- The objective is purely conversational without requiring any action
|
|
63
|
+
|
|
64
|
+
**Plan tasks when:**
|
|
65
|
+
- The objective requires gathering information from the file system, code, or documentation
|
|
66
|
+
- The objective requires analysis, processing, or computation to be performed
|
|
67
|
+
- Additional information must be collected before a complete response can be given
|
|
68
|
+
|
|
69
|
+
### 2. Analyze Information Requirements
|
|
70
|
+
|
|
71
|
+
If tasks are needed, think about the current state and objective:
|
|
72
|
+
- What information is needed to complete the objective?
|
|
73
|
+
- Where can this information be obtained from? (directory structure, config files, source code, documentation, etc.)
|
|
74
|
+
- What information has already been collected? What is still missing?
|
|
75
|
+
- Is deeper exploration needed, or is it ready to generate a summary?
|
|
76
|
+
|
|
77
|
+
### 3. Decision Principles
|
|
78
|
+
|
|
79
|
+
- **Plan only one specific task at a time**: Don't try to plan all steps at once
|
|
80
|
+
- **Only decide, don't execute**: You only output task descriptions, actual execution is done by the Worker
|
|
81
|
+
- **Trust the iterative process**: You will be called again after each task completes, allowing you to adjust the plan dynamically
|
|
82
|
+
- **Avoid duplicate work**: Review the execution history to understand what has been completed
|
|
83
|
+
- **Goal-oriented descriptions**: Task descriptions should state "what to do", not "how to do it"
|
|
84
|
+
|
|
85
|
+
### 4. Decision Making at Different Stages
|
|
86
|
+
|
|
87
|
+
Flexibly decide the next step based on current progress:
|
|
88
|
+
|
|
89
|
+
**Exploration Stage**:
|
|
90
|
+
- Plan exploration tasks, specifying which directories or files to examine
|
|
91
|
+
- Gradually collect information, focusing on one aspect at a time
|
|
92
|
+
|
|
93
|
+
**Summary Stage**:
|
|
94
|
+
- When sufficient information is collected, plan to generate a summary or report task
|
|
95
|
+
|
|
96
|
+
**Completion Stage**:
|
|
97
|
+
- Set `finished: true` when:
|
|
98
|
+
- The objective doesn't require any tasks (simple greetings, already answered questions)
|
|
99
|
+
- All necessary tasks are completed
|
|
100
|
+
- The objective is fully achieved
|
|
101
|
+
- This will trigger the Completer to integrate all information and generate the final report
|
|
102
|
+
|
|
103
|
+
### Supplementary rules
|
|
104
|
+
{{ customPlannerPrompt }}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## Output Format
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
nextTask: "[task description]" # optional, describe the next task to be performed to achieve the objective, null if no further tasks are needed
|
|
111
|
+
finished: false # set to true if no further tasks are needed and the objective is achieved
|
|
112
|
+
reasoning: "[brief explanation]" # optional, explain why this task is needed
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Note: Task descriptions should be **goal-oriented**, not specifying concrete operations. Let the worker autonomously decide how to complete the task based on the task objective.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
You are a task execution agent. Your job is to execute the specific task assigned to you - nothing more, nothing less.
|
|
2
|
+
|
|
3
|
+
## Environment
|
|
4
|
+
|
|
5
|
+
{{ $afs.description }}
|
|
6
|
+
|
|
7
|
+
```yaml alt="The modules available in the AFS"
|
|
8
|
+
{{ $afs.modules | yaml.stringify }}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The workspace directory is located at: `/modules/workspace/`
|
|
12
|
+
The DocSmith directory is located at: `/modules/doc-smith/`
|
|
13
|
+
|
|
14
|
+
## User's Objective
|
|
15
|
+
|
|
16
|
+
```txt alt="The user's objective provide for context only"
|
|
17
|
+
{{ objective }}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**CRITICAL CONSTRAINT**: The objective above is provided ONLY for context. You must NOT attempt to:
|
|
21
|
+
- Solve the entire objective
|
|
22
|
+
- Plan additional steps beyond your current task
|
|
23
|
+
- Make decisions about what should happen next
|
|
24
|
+
- Execute any tasks other than the one explicitly assigned to you below
|
|
25
|
+
|
|
26
|
+
## Latest Execution State
|
|
27
|
+
|
|
28
|
+
```yaml alt="The latest execution state for your reference"
|
|
29
|
+
{{ executionState | yaml.stringify }}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Your Current Task
|
|
33
|
+
|
|
34
|
+
```txt alt="The specific task you need to execute now"
|
|
35
|
+
{{ task }}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Important Instructions
|
|
39
|
+
- Focus EXCLUSIVELY on completing the current task described above
|
|
40
|
+
- The task is self-contained - execute it completely and accurately
|
|
41
|
+
- Do NOT perform additional tasks beyond what is specified
|
|
42
|
+
- Do NOT try to determine what should happen after this task
|
|
43
|
+
- Use the available tools and skills to accomplish this specific task
|
|
44
|
+
- Return a clear result that the planner can use to decide the next step
|
|
45
|
+
|
|
46
|
+
## Domain Knowledge
|
|
47
|
+
{{ domainKnowledge }}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Output Format
|
|
51
|
+
Return your task execution result as a structured response. The output schema will guide you on the required fields.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
type: team
|
|
2
|
+
name: DocSmith
|
|
3
|
+
alias:
|
|
4
|
+
- run
|
|
5
|
+
description: DocSmith entry point for documentation generation, editing, and translation
|
|
6
|
+
input_schema:
|
|
7
|
+
type: object
|
|
8
|
+
properties:
|
|
9
|
+
message:
|
|
10
|
+
type: string
|
|
11
|
+
description: User feedback describing what documentation tasks to perform (natural language)
|
|
12
|
+
changeset:
|
|
13
|
+
type: string
|
|
14
|
+
description: 通过 Changeset 描述一批希望执行的变更
|
|
15
|
+
required: []
|
|
16
|
+
|
|
17
|
+
skills:
|
|
18
|
+
- url: ../../agents/init/index.mjs
|
|
19
|
+
default_input:
|
|
20
|
+
skipIfExists: true
|
|
21
|
+
- ../utils/load-base-sources.mjs
|
|
22
|
+
- ./set-custom-prompt.mjs
|
|
23
|
+
- type: "@aigne/agent-library/orchestrator"
|
|
24
|
+
objective:
|
|
25
|
+
url: objective.md
|
|
26
|
+
|
|
27
|
+
planner:
|
|
28
|
+
type: ai
|
|
29
|
+
model: anthropic/claude-opus-4-5-20251101
|
|
30
|
+
instructions:
|
|
31
|
+
url: ../common/planner.md
|
|
32
|
+
input_schema:
|
|
33
|
+
type: object
|
|
34
|
+
properties:
|
|
35
|
+
plannerInitState:
|
|
36
|
+
type: string
|
|
37
|
+
description: The initial state of the planner
|
|
38
|
+
customPlannerPrompt:
|
|
39
|
+
type: string
|
|
40
|
+
description: The custom planner prompt
|
|
41
|
+
|
|
42
|
+
worker:
|
|
43
|
+
type: ai
|
|
44
|
+
# model: anthropic/claude-opus-4-5-20251101
|
|
45
|
+
instructions:
|
|
46
|
+
url: ../common/worker.md
|
|
47
|
+
input_schema:
|
|
48
|
+
type: object
|
|
49
|
+
properties:
|
|
50
|
+
domainKnowledge:
|
|
51
|
+
type: string
|
|
52
|
+
description: The domain knowledge
|
|
53
|
+
skills:
|
|
54
|
+
- ../structure/index.yaml
|
|
55
|
+
- ../detail/index.yaml
|
|
56
|
+
|
|
57
|
+
completer:
|
|
58
|
+
type: function
|
|
59
|
+
process: |
|
|
60
|
+
let message = 'All tasks have been completed.';
|
|
61
|
+
return { message };
|
|
62
|
+
|
|
63
|
+
state_management:
|
|
64
|
+
max_iterations: 50
|
|
65
|
+
max_tokens: 200000
|
|
66
|
+
keep_recent: 30
|
|
67
|
+
|
|
68
|
+
afs:
|
|
69
|
+
modules:
|
|
70
|
+
- module: local-fs
|
|
71
|
+
options:
|
|
72
|
+
name: doc-smith
|
|
73
|
+
localPath: .aigne/doc-smith
|
|
74
|
+
description: The Doc Smith workspace for storing intermediate and output files
|
|
75
|
+
- module: local-fs
|
|
76
|
+
options:
|
|
77
|
+
name: workspace
|
|
78
|
+
localPath: .
|
|
79
|
+
description: The target repository containing source code and documentation. Read-only, cannot be modified.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{% if structureContent %}
|
|
2
|
+
文档已在 `/modules/doc-smith`目录下生成:
|
|
3
|
+
1. 检查文档结构中的每篇都已生成了详情,如果有缺失,请为缺失的文档生成详情
|
|
4
|
+
2. 根据我的反馈修改文档
|
|
5
|
+
{% else %}
|
|
6
|
+
请为当前仓库生成文档:
|
|
7
|
+
1. 生成文档结构
|
|
8
|
+
2. 为文档结构中的每篇文档生成详情
|
|
9
|
+
{% endif %}
|
|
10
|
+
|
|
11
|
+
我对文档的要求:
|
|
12
|
+
文档使用 {{locale }} 语言。
|
|
13
|
+
|
|
14
|
+
{% if rules %}
|
|
15
|
+
{{ rules }}
|
|
16
|
+
{% endif %}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
{% if message %}
|
|
20
|
+
我的反馈意见:
|
|
21
|
+
{{ message }}
|
|
22
|
+
{% endif %}
|
|
23
|
+
|
|
24
|
+
{% if changeset %}
|
|
25
|
+
请分析我反馈的 ChangeSet ,规划任务实施修改:
|
|
26
|
+
```txt
|
|
27
|
+
{{ changeset }}
|
|
28
|
+
```
|
|
29
|
+
{% endif %}
|
|
30
|
+
|
|
31
|
+
{% if structureContent %}
|
|
32
|
+
检查并处理 PATCH
|
|
33
|
+
搜索文档中的 patch (::: PATCH),根据 patch 中的要求修改文档,修改完成后删除对应的 patch。
|
|
34
|
+
|
|
35
|
+
示例:
|
|
36
|
+
::: PATCH
|
|
37
|
+
# Original
|
|
38
|
+
DocSmith 直接修改用户文档并写回到原项目。
|
|
39
|
+
|
|
40
|
+
# Revised
|
|
41
|
+
DocSmith 永远不直接 touch 用户原始 repo,而是
|
|
42
|
+
在独立 workspace 中生成版本化产物,再通过 patch 合并。
|
|
43
|
+
:::
|
|
44
|
+
{% endif %}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
// FIXME: 临时使用这种方式设置自定义变量,框架优化后需要修改
|
|
9
|
+
export default function getCustomPrompt({ structureContent }) {
|
|
10
|
+
let finalStructureContent = "文档结构未生成";
|
|
11
|
+
if (structureContent) {
|
|
12
|
+
finalStructureContent = `
|
|
13
|
+
\`\`\`yaml\n${structureContent}\n\`\`\`
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
const plannerInitState = `
|
|
17
|
+
文档结构(/modules/doc-smith/output/document_structure.yaml):
|
|
18
|
+
${finalStructureContent}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const customPlannerPrompt = `
|
|
22
|
+
- 文档结构相关的任务与文档内容相关的任务需要拆分为独立的任务
|
|
23
|
+
- 你只需要读取少量信息来规划任务,深度的信息读取由 Worker 完成
|
|
24
|
+
- 可以在同一个任务中规划多篇文档的生成/更新任务,Worker 中可以批量处理提升效率
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const baseInfoPath = path.join(__dirname, "../common/base-info.md");
|
|
28
|
+
const baseInfo = fs.readFileSync(baseInfoPath, "utf-8");
|
|
29
|
+
|
|
30
|
+
const domainKnowledge = `
|
|
31
|
+
${baseInfo}
|
|
32
|
+
|
|
33
|
+
### 使用用文档相关的 Skill 完成任务
|
|
34
|
+
文档结构相关的任务使用:GenerateStructure
|
|
35
|
+
文档内容相关的任务使用:GenerateDetail
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
plannerInitState,
|
|
40
|
+
customPlannerPrompt,
|
|
41
|
+
domainKnowledge,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type: team
|
|
2
|
+
name: GenerateDetail
|
|
3
|
+
description: Generate or update detailed content for multiple documentation files
|
|
4
|
+
input_schema:
|
|
5
|
+
type: object
|
|
6
|
+
properties:
|
|
7
|
+
rules:
|
|
8
|
+
type: string
|
|
9
|
+
description: Your specific requirements for documentation structure
|
|
10
|
+
locale:
|
|
11
|
+
type: string
|
|
12
|
+
description: Primary language for documentation (e.g., zh, en, ja)
|
|
13
|
+
tasks:
|
|
14
|
+
type: array
|
|
15
|
+
description: Tasks describing which documents to generate/update, including title, path, description, sourcePaths, and task description
|
|
16
|
+
items:
|
|
17
|
+
type: object
|
|
18
|
+
properties:
|
|
19
|
+
task:
|
|
20
|
+
type: string
|
|
21
|
+
description: Task describing which document to generate/update, including title, path, description, sourcePaths, and task description
|
|
22
|
+
iterate_on: tasks
|
|
23
|
+
concurrency: 5
|
|
24
|
+
skills:
|
|
25
|
+
- ../utils/load-base-sources.mjs
|
|
26
|
+
- ./set-custom-prompt.mjs
|
|
27
|
+
- type: "@aigne/agent-library/orchestrator"
|
|
28
|
+
input_schema:
|
|
29
|
+
type: object
|
|
30
|
+
properties:
|
|
31
|
+
task:
|
|
32
|
+
type: string
|
|
33
|
+
description: Task describing which document to generate/update, including title, path, description, sourcePaths, and task description
|
|
34
|
+
rules:
|
|
35
|
+
type: string
|
|
36
|
+
description: Your specific requirements for documentation content
|
|
37
|
+
locale:
|
|
38
|
+
type: string
|
|
39
|
+
description: Primary language for documentation (e.g., zh, en, ja)
|
|
40
|
+
objective:
|
|
41
|
+
url: objective.md
|
|
42
|
+
planner:
|
|
43
|
+
type: ai
|
|
44
|
+
model: anthropic/claude-opus-4-5-20251101
|
|
45
|
+
instructions:
|
|
46
|
+
url: ../common/planner.md
|
|
47
|
+
input_schema:
|
|
48
|
+
type: object
|
|
49
|
+
properties:
|
|
50
|
+
plannerInitState:
|
|
51
|
+
type: string
|
|
52
|
+
description: The initial state of the planner
|
|
53
|
+
customPlannerPrompt:
|
|
54
|
+
type: string
|
|
55
|
+
description: The custom planner prompt
|
|
56
|
+
worker:
|
|
57
|
+
type: ai
|
|
58
|
+
instructions:
|
|
59
|
+
url: ../common/worker.md
|
|
60
|
+
input_schema:
|
|
61
|
+
type: object
|
|
62
|
+
properties:
|
|
63
|
+
domainKnowledge:
|
|
64
|
+
type: string
|
|
65
|
+
description: The domain knowledge
|
|
66
|
+
completer:
|
|
67
|
+
type: function
|
|
68
|
+
process: |
|
|
69
|
+
let message = 'All tasks have been completed.';
|
|
70
|
+
return { message };
|
|
71
|
+
afs:
|
|
72
|
+
modules:
|
|
73
|
+
- module: local-fs
|
|
74
|
+
options:
|
|
75
|
+
name: workspace
|
|
76
|
+
localPath: .
|
|
77
|
+
description: The target repository containing source code and documentation. Read-only, cannot be modified.
|
|
78
|
+
- module: local-fs
|
|
79
|
+
options:
|
|
80
|
+
name: doc-smith
|
|
81
|
+
localPath: .aigne/doc-smith
|
|
82
|
+
description: The Doc Smith workspace for storing intermediate and output files
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
// FIXME: 临时使用这种方式设置自定义变量,框架优化后需要修改
|
|
9
|
+
export default function getCustomPrompt({ structureContent }) {
|
|
10
|
+
let finalStructureContent = "文档结构未生成";
|
|
11
|
+
if (structureContent) {
|
|
12
|
+
finalStructureContent = `
|
|
13
|
+
\`\`\`yaml\n${structureContent}\n\`\`\`
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const plannerInitState = `
|
|
18
|
+
文档结构(/modules/doc-smith/output/document_structure.yaml):
|
|
19
|
+
${finalStructureContent}
|
|
20
|
+
`;
|
|
21
|
+
const customPlannerPrompt = `
|
|
22
|
+
- 首先确定需要处理的是文档结构中的哪一篇文档
|
|
23
|
+
- 检查文档是否已存在,决定是生成新文档还是更新现有文档
|
|
24
|
+
- 文档详情以 markdown 的格式输出在 /modules/doc-smith/docs 目录中,根据文档的 \`path\` 生成文件名。
|
|
25
|
+
- 读取 sourcePaths 中的文件作为初始上下文,按需求读取更多的相关文件作为上下文
|
|
26
|
+
- 生成文档内容后,review 文档内容,确保符合文档质量标准
|
|
27
|
+
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const baseInfoPath = path.join(__dirname, "../common/base-info.md");
|
|
31
|
+
const baseInfo = fs.readFileSync(baseInfoPath, "utf-8");
|
|
32
|
+
|
|
33
|
+
const domainKnowledge = `
|
|
34
|
+
${baseInfo}
|
|
35
|
+
|
|
36
|
+
### 文档质量标准
|
|
37
|
+
|
|
38
|
+
#### 深度要求
|
|
39
|
+
|
|
40
|
+
每篇文档应该:
|
|
41
|
+
- 基于 sourcePaths 中的数据源生成详细准确的内容
|
|
42
|
+
- 根据需要读取更多相关数据源作为上下文
|
|
43
|
+
- 每个章节应尽可能参考更多相关数据源,使生成的文档详细准确
|
|
44
|
+
|
|
45
|
+
文档应该是**生产级别、可直接使用**的,而不是简单概述。
|
|
46
|
+
|
|
47
|
+
#### 必须包含的内容
|
|
48
|
+
|
|
49
|
+
- **代码示例**: 可运行的完整代码,包含必要的 import 语句
|
|
50
|
+
- **响应数据示例**: 所有接口和方法必须包含响应数据示例
|
|
51
|
+
- **配置参数说明**: 全面解释配置选项和参数,多值参数需解释每个选项的用途
|
|
52
|
+
|
|
53
|
+
#### 标准结构
|
|
54
|
+
|
|
55
|
+
每篇文档包含:
|
|
56
|
+
- **标题层级正确**: 总是以一级标题开始,标题层级连续
|
|
57
|
+
- **Opening Hook**: 简洁有力(≤50 词),说明读者将获得什么
|
|
58
|
+
- **引言**: 包含相关文档内链
|
|
59
|
+
- **主体**: 多个小节,含代码示例和说明
|
|
60
|
+
- **总结**: 包含延伸阅读链接(引导阅读其他相关文档)
|
|
61
|
+
|
|
62
|
+
#### 写作风格
|
|
63
|
+
|
|
64
|
+
- 简洁、严谨、准确
|
|
65
|
+
- 为人类写作,不是为算法
|
|
66
|
+
- 主动语态优先,可混用被动
|
|
67
|
+
- 直接表达: 发生了什么、为什么重要、如何帮助
|
|
68
|
+
|
|
69
|
+
#### 信息获取
|
|
70
|
+
|
|
71
|
+
- workspace 中的数据源需要主动探索和搜索
|
|
72
|
+
- 基于实际找到的信息生成文档
|
|
73
|
+
- 不编造或假设不存在的功能
|
|
74
|
+
|
|
75
|
+
#### 数据源使用
|
|
76
|
+
|
|
77
|
+
- 公开产品/技术: 可用已有知识补充
|
|
78
|
+
- 私有产品: 不能编造虚假信息
|
|
79
|
+
- 信息不足: 说明需要更多上下文
|
|
80
|
+
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
plannerInitState,
|
|
85
|
+
customPlannerPrompt,
|
|
86
|
+
domainKnowledge,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
1. **sourcePaths Must Be Files**: This is CRITICAL - `sourcePaths` must contain only file paths, never directory paths
|
|
3
|
+
- ✅ Correct: `["README.md", "src/index.ts", "docs/guide.md"]`
|
|
4
|
+
- ❌ Wrong: `["src/", "docs/", "src/components/"]`
|
|
5
|
+
- Must be relative paths from workspace root, **without** the `/modules/workspace` prefix
|
|
6
|
+
- Examples: `src/index.ts`, `README.md`, `package.json`, `docs/api.md`
|
|
7
|
+
|
|
8
|
+
2. **Prioritize Based on Project Focus**: Use insights from README and docs to guide structure
|
|
9
|
+
- If README highlights specific features, create dedicated sections for them
|
|
10
|
+
- If the project emphasizes certain workflows, mirror this in structure
|
|
11
|
+
- Create documentation that helps users understand what the project owners consider most important
|
|
12
|
+
|
|
13
|
+
3. **Create a Logical, User-Focused Hierarchy**:
|
|
14
|
+
- Start with what users need first (overview, quick start, core concepts)
|
|
15
|
+
- Follow with detailed sections for key features
|
|
16
|
+
- Include advanced topics and reference material later
|
|
17
|
+
- Each document section should have a distinct, non-overlapping purpose
|
|
18
|
+
|
|
19
|
+
4. **Focus on Project Domain, Not Build System**: For code projects, focus documentation on the project's core purpose and functionality, NOT on build/tooling infrastructure
|
|
20
|
+
- ✅ **Include**: Project features, APIs, architecture, usage guides, domain concepts
|
|
21
|
+
- ❌ **Exclude**: Build system docs (webpack config, rollup setup, vite config), CI/CD pipelines, development tooling setup, linting/formatting configuration
|
|
22
|
+
- **Exception**: Only include build/tooling docs if the project IS a build tool
|
|
23
|
+
|
|
24
|
+
5. **For Multi-Package Projects**: Create hierarchical documentation structure
|
|
25
|
+
- Start with overview documentation (getting started, architecture overview)
|
|
26
|
+
- Create a parent section for each package/module with clear naming
|
|
27
|
+
- Under each package section, add child sections for that package's specific documentation
|
|
28
|
+
- Include cross-package documentation (how packages interact, dependency graph)
|
|
29
|
+
|
|
30
|
+
6. **sourcePaths Should Be Comprehensive**:
|
|
31
|
+
- Include as many related files as possible to ensure quality of subsequent detail generation
|
|
32
|
+
- If analyzing source code, include related and adjacent source code files
|
|
33
|
+
- Analyze referenced files within the source code and include them too
|
|
34
|
+
- **Ensure sourcePaths are never empty** - Do not create document sections without related data sources
|
|
35
|
+
|
|
36
|
+
7. **Character Length Constraints**:
|
|
37
|
+
- `project.title`: Must not exceed **40 characters** (all languages count equally)
|
|
38
|
+
- `project.description`: Must not exceed **160 characters** (all languages count equally)
|
|
39
|
+
- Ensure generated content is complete and grammatically correct within these constraints
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
type: team
|
|
2
|
+
name: GenerateStructure
|
|
3
|
+
# model: anthropic/claude-opus-4-5-20251101
|
|
4
|
+
description: Generate the structure of your documentation
|
|
5
|
+
input_schema:
|
|
6
|
+
type: object
|
|
7
|
+
properties:
|
|
8
|
+
rules:
|
|
9
|
+
type: string
|
|
10
|
+
description: Your specific requirements for documentation structure
|
|
11
|
+
locale:
|
|
12
|
+
type: string
|
|
13
|
+
description: Primary language for documentation (e.g., zh, en, ja)
|
|
14
|
+
task:
|
|
15
|
+
type: string
|
|
16
|
+
description: Task related to this documentation structure
|
|
17
|
+
skills:
|
|
18
|
+
- ../utils/load-base-sources.mjs
|
|
19
|
+
- ./set-custom-prompt.mjs
|
|
20
|
+
- type: "@aigne/agent-library/orchestrator"
|
|
21
|
+
objective:
|
|
22
|
+
url: objective.md
|
|
23
|
+
planner:
|
|
24
|
+
type: ai
|
|
25
|
+
model: anthropic/claude-opus-4-5-20251101
|
|
26
|
+
instructions:
|
|
27
|
+
url: ../common/planner.md
|
|
28
|
+
input_schema:
|
|
29
|
+
type: object
|
|
30
|
+
properties:
|
|
31
|
+
plannerInitState:
|
|
32
|
+
type: string
|
|
33
|
+
description: The initial state of the planner
|
|
34
|
+
customPlannerPrompt:
|
|
35
|
+
type: string
|
|
36
|
+
description: The custom planner prompt
|
|
37
|
+
worker:
|
|
38
|
+
type: ai
|
|
39
|
+
instructions:
|
|
40
|
+
url: ../common/worker.md
|
|
41
|
+
input_schema:
|
|
42
|
+
type: object
|
|
43
|
+
properties:
|
|
44
|
+
domainKnowledge:
|
|
45
|
+
type: string
|
|
46
|
+
description: The domain knowledge
|
|
47
|
+
completer:
|
|
48
|
+
type: function
|
|
49
|
+
process: |
|
|
50
|
+
let message = 'All tasks have been completed.';
|
|
51
|
+
return { message };
|
|
52
|
+
afs:
|
|
53
|
+
modules:
|
|
54
|
+
- module: local-fs
|
|
55
|
+
options:
|
|
56
|
+
name: workspace
|
|
57
|
+
localPath: .
|
|
58
|
+
description: The target repository containing source code and documentation. Read-only, cannot be modified.
|
|
59
|
+
- module: local-fs
|
|
60
|
+
options:
|
|
61
|
+
name: doc-smith
|
|
62
|
+
localPath: .aigne/doc-smith
|
|
63
|
+
description: The Doc Smith workspace for storing intermediate and output files
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
1. **YAML Format Correctness** - Automatic rejection if:
|
|
3
|
+
- Indentation is not exactly 2 spaces per level
|
|
4
|
+
- Missing spaces after colons (e.g., `title:"value"` instead of `title: "value"`)
|
|
5
|
+
- List items don't start with `- ` (dash + space)
|
|
6
|
+
- Special characters are not properly quoted
|
|
7
|
+
- Any YAML syntax errors that would cause parsing to fail
|
|
8
|
+
|
|
9
|
+
2. **Valid sourcePaths** - Automatic rejection if:
|
|
10
|
+
- ANY `sourcePaths` entry contains a directory path (e.g., `src/`, `docs/`)
|
|
11
|
+
- ANY `sourcePaths` entry includes the `/modules/workspace` prefix
|
|
12
|
+
- ANY `sourcePaths` entry uses absolute paths
|
|
13
|
+
- ✅ Valid examples: `README.md`, `src/index.ts`, `docs/api.md`
|
|
14
|
+
- ❌ Invalid examples: `src/`, `/modules/workspace/README.md`, `/absolute/path/file.ts`
|
|
15
|
+
|
|
16
|
+
3. **Project Domain Focus** - Automatic rejection if:
|
|
17
|
+
- Structure includes build/tooling documentation for non-build-tool projects (e.g., "Webpack Configuration", "CI/CD Pipeline", "ESLint Rules")
|
|
18
|
+
- Documentation focuses on internal development infrastructure instead of project features
|
|
19
|
+
- ✅ Approve: Project features, APIs, architecture, usage guides, domain concepts
|
|
20
|
+
- ❌ Reject: Build configs, CI/CD, linting setup (unless the project IS a build tool)
|
|
21
|
+
|
|
22
|
+
## Quality Assessment Checks
|
|
23
|
+
|
|
24
|
+
4. **Adequate Coverage and Depth**
|
|
25
|
+
- Reject if structure is too minimal (only 1-2 sections for non-trivial projects)
|
|
26
|
+
- Reject if missing obvious sections (e.g., no API docs for a library, no getting-started guide)
|
|
27
|
+
- Approve if structure has appropriate breadth and depth
|
|
28
|
+
|
|
29
|
+
5. **Project Priorities Alignment**
|
|
30
|
+
- Reject if structure ignores key features emphasized in README/documentation
|
|
31
|
+
- Approve if key features from README have dedicated sections
|
|
32
|
+
|
|
33
|
+
6. **Multi-Package/Monorepo Structure** (if applicable)
|
|
34
|
+
- Reject if ANY package section lacks nested children subsections
|
|
35
|
+
- Approve if each package has its own section with children organizing package-specific docs
|
|
36
|
+
|
|
37
|
+
7. **No Duplicate Sections**
|
|
38
|
+
- Reject if multiple sections have the same purpose without clear differentiation
|
|
39
|
+
|
|
40
|
+
8. **Clear Section Purposes**
|
|
41
|
+
- Reject if section titles are vague (e.g., "Other", "Misc", "Files")
|
|
42
|
+
|
|
43
|
+
## Review Decision Making
|
|
44
|
+
|
|
45
|
+
**If user feedback exists**:
|
|
46
|
+
- ONLY verify that structure changes address the user's specific feedback
|
|
47
|
+
- Ignore all standard quality criteria
|
|
48
|
+
- Approve if user's requirements are met, even if other issues exist
|
|
49
|
+
|
|
50
|
+
**If no user feedback**:
|
|
51
|
+
- Apply all quality criteria strictly
|
|
52
|
+
- Reject if any critical validation fails
|
|
53
|
+
- Reject if multiple quality issues exist
|
|
54
|
+
|
|
55
|
+
**If rejected**: Loop back to design phase and regenerate based on review feedback
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
// FIXME: 临时使用这种方式设置自定义变量,框架优化后需要修改
|
|
9
|
+
export default function getCustomPrompt({ structureContent }) {
|
|
10
|
+
let finalStructureContent = "文档结构未生成";
|
|
11
|
+
if (structureContent) {
|
|
12
|
+
finalStructureContent = `
|
|
13
|
+
\`\`\`yaml\n${structureContent}\n\`\`\`
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
const plannerInitState = `
|
|
17
|
+
文档结构(/modules/doc-smith/output/document_structure.yaml):
|
|
18
|
+
${finalStructureContent}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const customPlannerPrompt = `
|
|
22
|
+
- 文档结构生成之后,需要按照'质量审查标准',进行质量审查,并修复发现的问题
|
|
23
|
+
- 关键: 在保存 YAML 文件之前,严格验证格式:
|
|
24
|
+
|
|
25
|
+
✅ **正确格式示例:**
|
|
26
|
+
\`\`\`yaml
|
|
27
|
+
project:
|
|
28
|
+
title: "我的项目"
|
|
29
|
+
description: "项目的简要描述"
|
|
30
|
+
|
|
31
|
+
documents:
|
|
32
|
+
- title: "概览"
|
|
33
|
+
description: "项目介绍"
|
|
34
|
+
path: /overview.md
|
|
35
|
+
sourcePaths:
|
|
36
|
+
- README.md
|
|
37
|
+
- docs/intro.md
|
|
38
|
+
children: []
|
|
39
|
+
- title: "API 参考"
|
|
40
|
+
description: "完整的 API 文档"
|
|
41
|
+
path: /api-Reference.md
|
|
42
|
+
sourcePaths:
|
|
43
|
+
- docs/api.md
|
|
44
|
+
children:
|
|
45
|
+
- title: "核心 API"
|
|
46
|
+
path: /core-api.md
|
|
47
|
+
description: "核心功能"
|
|
48
|
+
sourcePaths:
|
|
49
|
+
- docs/api/core.md
|
|
50
|
+
children: []
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
❌ **要避免的常见错误:**
|
|
54
|
+
1. 冒号后缺少空格: \`title:"测试"\` (错误) → \`title: "测试"\` (正确)
|
|
55
|
+
2. 错误的缩进: 每级必须恰好 2 个空格
|
|
56
|
+
3. 列表项缺少破折号: \`documents: title: "测试"\` (错误) → \`documents: - title: "测试"\` (正确)
|
|
57
|
+
4. sourcePaths 中的目录路径: \`sourcePaths: - src/\` (错误) → \`sourcePaths: - src/index.ts\` (正确)
|
|
58
|
+
5. 包含模块前缀: \`/modules/workspace/README.md\` (错误) → \`README.md\` (正确)
|
|
59
|
+
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
const baseInfoPath = path.join(__dirname, "../common/base-info.md");
|
|
63
|
+
const baseInfo = fs.readFileSync(baseInfoPath, "utf-8");
|
|
64
|
+
|
|
65
|
+
const domainKnowledge = `
|
|
66
|
+
${baseInfo}
|
|
67
|
+
|
|
68
|
+
### 使用用文档相关的 Skill 完成任务
|
|
69
|
+
文档结构相关的任务使用:GenerateStructure
|
|
70
|
+
文档内容相关的任务使用:GenerateDetail
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
plannerInitState,
|
|
75
|
+
customPlannerPrompt,
|
|
76
|
+
domainKnowledge,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
async function buildDirectoryTree(dirPath) {
|
|
5
|
+
const entries = [];
|
|
6
|
+
|
|
7
|
+
async function scanDir(currentPath, relativePath = "") {
|
|
8
|
+
try {
|
|
9
|
+
const items = await readdir(currentPath);
|
|
10
|
+
|
|
11
|
+
for (const item of items) {
|
|
12
|
+
const fullPath = join(currentPath, item);
|
|
13
|
+
const itemRelativePath = relativePath ? `${relativePath}/${item}` : `/${item}`;
|
|
14
|
+
const stats = await stat(fullPath);
|
|
15
|
+
|
|
16
|
+
entries.push({
|
|
17
|
+
path: itemRelativePath,
|
|
18
|
+
isDirectory: stats.isDirectory(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (stats.isDirectory()) {
|
|
22
|
+
await scanDir(fullPath, itemRelativePath);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// 忽略读取错误
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
await scanDir(dirPath);
|
|
31
|
+
return entries;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildTreeView(entries) {
|
|
35
|
+
const tree = {};
|
|
36
|
+
const entryMap = new Map();
|
|
37
|
+
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
entryMap.set(entry.path, entry);
|
|
40
|
+
const parts = entry.path.split("/").filter(Boolean);
|
|
41
|
+
let current = tree;
|
|
42
|
+
|
|
43
|
+
for (const part of parts) {
|
|
44
|
+
if (!current[part]) {
|
|
45
|
+
current[part] = {};
|
|
46
|
+
}
|
|
47
|
+
current = current[part];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function renderTree(node, prefix = "", currentPath = "") {
|
|
52
|
+
let result = "";
|
|
53
|
+
const keys = Object.keys(node);
|
|
54
|
+
keys.forEach((key, index) => {
|
|
55
|
+
const isLast = index === keys.length - 1;
|
|
56
|
+
const fullPath = currentPath ? `${currentPath}/${key}` : `/${key}`;
|
|
57
|
+
const entry = entryMap.get(fullPath);
|
|
58
|
+
|
|
59
|
+
const suffix = entry?.isDirectory ? "/" : "";
|
|
60
|
+
result += `${prefix}${isLast ? "└── " : "├── "}${key}${suffix}`;
|
|
61
|
+
result += "\n";
|
|
62
|
+
result += renderTree(node[key], `${prefix}${isLast ? " " : "│ "}`, fullPath);
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return renderTree(tree);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default async function loadBaseSources() {
|
|
71
|
+
const cwd = process.cwd();
|
|
72
|
+
const docSmithPath = join(cwd, ".aigne/doc-smith");
|
|
73
|
+
const structureFilePath = join(docSmithPath, "output/document_structure.yaml");
|
|
74
|
+
|
|
75
|
+
// 读取 document_structure.yaml 文件内容
|
|
76
|
+
let structureContent = "";
|
|
77
|
+
try {
|
|
78
|
+
structureContent = await readFile(structureFilePath, "utf-8");
|
|
79
|
+
} catch {
|
|
80
|
+
// 文件不存在时忽略错误
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 读取 .aigne/doc-smith 目录结构
|
|
84
|
+
let directoryTree = "";
|
|
85
|
+
try {
|
|
86
|
+
const entries = await buildDirectoryTree(docSmithPath);
|
|
87
|
+
directoryTree = buildTreeView(entries);
|
|
88
|
+
} catch {
|
|
89
|
+
// 目录不存在时忽略错误
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
structureContent,
|
|
94
|
+
directoryTree,
|
|
95
|
+
};
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/doc-smith",
|
|
3
|
-
"version": "0.9.8-alpha.
|
|
3
|
+
"version": "0.9.8-alpha.1",
|
|
4
4
|
"description": "AI-driven documentation generation tool built on the AIGNE Framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"agents",
|
|
10
|
+
"agentic-agents",
|
|
10
11
|
"assets/report-template",
|
|
11
12
|
"docs-mcp",
|
|
12
13
|
"prompts",
|