@blocklet/pages-kit-agents 0.5.41 → 0.5.42

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.
Files changed (30) hide show
  1. package/lib/cjs/agents/template-designer.d.ts +13 -0
  2. package/lib/cjs/agents/template-designer.js +67 -0
  3. package/lib/cjs/agents/template-generator.d.ts +18 -0
  4. package/lib/cjs/agents/template-generator.js +186 -0
  5. package/lib/cjs/tsconfig.tsbuildinfo +1 -1
  6. package/lib/cjs/utils/component-tuils.d.ts +12 -0
  7. package/lib/cjs/utils/component-tuils.js +141 -0
  8. package/lib/cjs/utils/file-utils.d.ts +23 -0
  9. package/lib/cjs/utils/file-utils.js +77 -0
  10. package/lib/cjs/workflow-agents/reflection-agent.d.ts +16 -0
  11. package/lib/cjs/workflow-agents/reflection-agent.js +38 -0
  12. package/lib/esm/agents/template-designer.d.ts +13 -0
  13. package/lib/esm/agents/template-designer.js +61 -0
  14. package/lib/esm/agents/template-generator.d.ts +18 -0
  15. package/lib/esm/agents/template-generator.js +180 -0
  16. package/lib/esm/tsconfig.tsbuildinfo +1 -1
  17. package/lib/esm/utils/component-tuils.d.ts +12 -0
  18. package/lib/esm/utils/component-tuils.js +136 -0
  19. package/lib/esm/utils/file-utils.d.ts +23 -0
  20. package/lib/esm/utils/file-utils.js +74 -0
  21. package/lib/esm/workflow-agents/reflection-agent.d.ts +16 -0
  22. package/lib/esm/workflow-agents/reflection-agent.js +34 -0
  23. package/lib/types/agents/template-designer.d.ts +13 -0
  24. package/lib/types/agents/template-generator.d.ts +18 -0
  25. package/lib/types/tsconfig.tsbuildinfo +1 -1
  26. package/lib/types/utils/component-tuils.d.ts +12 -0
  27. package/lib/types/utils/file-utils.d.ts +23 -0
  28. package/lib/types/workflow-agents/reflection-agent.d.ts +16 -0
  29. package/package.json +5 -2
  30. package/workflow-cli.ts +132 -0
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ export declare function getSchemaByComponentIds(sections: {
3
+ componentId: string;
4
+ componentName: string;
5
+ sectionName: string;
6
+ }[]): z.ZodObject<Record<string, any>, "strip", z.ZodTypeAny, {
7
+ [x: string]: any;
8
+ }, {
9
+ [x: string]: any;
10
+ }>;
11
+ export declare function getComponentsSimpleMetadata(): string;
12
+ export declare function getComponentsMetadata(): string;
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSchemaByComponentIds = getSchemaByComponentIds;
4
+ exports.getComponentsSimpleMetadata = getComponentsSimpleMetadata;
5
+ exports.getComponentsMetadata = getComponentsMetadata;
6
+ const zod_utils_1 = require("@blocklet/pages-kit-block-studio/zod-utils");
7
+ const zod_1 = require("zod");
8
+ const componentList = [
9
+ {
10
+ name: 'HeroV2',
11
+ id: '1',
12
+ description: 'Hero 区域,展示核心价值主张,主 CTA',
13
+ properties: zod_1.z.object({
14
+ title: zod_1.z.string().describe('主标题'),
15
+ description: zod_1.z.string().describe('描述'),
16
+ image: zod_1.z.string().describe('图片'),
17
+ buttons: zod_1.z
18
+ .array(zod_1.z.object({
19
+ text: zod_1.z.string().describe('按钮文本'),
20
+ link: zod_1.z.string().describe('按钮链接'),
21
+ }))
22
+ .describe('按钮列表'),
23
+ }),
24
+ },
25
+ {
26
+ name: 'ContentCards',
27
+ id: '2',
28
+ description: 'Hero、Features 、 Benefits、How it Works、',
29
+ properties: zod_1.z.object({
30
+ title: zod_1.z.string().describe('标题'),
31
+ description: zod_1.z.string().describe('描述'),
32
+ list: zod_1.z
33
+ .array(zod_1.z.object({
34
+ title: zod_1.z.string().describe('标题'),
35
+ description: zod_1.z.string().describe('描述'),
36
+ image: zod_1.z.string().describe('图片'),
37
+ }))
38
+ .describe('列表'),
39
+ }),
40
+ },
41
+ {
42
+ name: 'FAQ',
43
+ id: '3',
44
+ description: 'FAQ 区域,展示常见问题及答案',
45
+ properties: zod_1.z.object({
46
+ title: zod_1.z.string().describe('标题'),
47
+ list: zod_1.z
48
+ .array(zod_1.z.object({
49
+ question: zod_1.z.string().describe('问题'),
50
+ answer: zod_1.z.string().describe('答案'),
51
+ }))
52
+ .describe('列表'),
53
+ }),
54
+ },
55
+ {
56
+ name: 'Pricing',
57
+ id: '4',
58
+ description: 'Pricing 区域,展示价格方案',
59
+ properties: zod_1.z.object({
60
+ title: zod_1.z.string().describe('标题'),
61
+ list: zod_1.z
62
+ .array(zod_1.z.object({
63
+ title: zod_1.z.string().describe('标题'),
64
+ description: zod_1.z.string().describe('描述'),
65
+ price: zod_1.z.string().describe('价格'),
66
+ }))
67
+ .describe('列表'),
68
+ }),
69
+ },
70
+ {
71
+ name: 'CTA',
72
+ id: '5',
73
+ description: 'CTA 区域,展示最终行动召唤',
74
+ properties: zod_1.z.object({
75
+ title: zod_1.z.string().describe('标题'),
76
+ description: zod_1.z.string().describe('描述'),
77
+ buttons: zod_1.z
78
+ .array(zod_1.z.object({
79
+ text: zod_1.z.string().describe('按钮文本'),
80
+ link: zod_1.z.string().describe('按钮链接'),
81
+ }))
82
+ .describe('按钮列表'),
83
+ }),
84
+ },
85
+ {
86
+ name: 'Logo List',
87
+ id: '6',
88
+ description: 'Logo 列表,展示合作伙伴',
89
+ properties: zod_1.z.object({
90
+ title: zod_1.z.string().describe('标题'),
91
+ list: zod_1.z
92
+ .array(zod_1.z.object({
93
+ image: zod_1.z.string().describe('图片'),
94
+ name: zod_1.z.string().describe('名称'),
95
+ link: zod_1.z.string().describe('链接'),
96
+ }))
97
+ .describe('列表'),
98
+ }),
99
+ },
100
+ ];
101
+ function getSchemaByComponentIds(sections) {
102
+ const schemaObject = {};
103
+ sections.forEach((section) => {
104
+ const component = componentList.find((comp) => comp.id === section.componentId);
105
+ if (component) {
106
+ schemaObject[section.sectionName] = component.properties;
107
+ }
108
+ });
109
+ return zod_1.z.object(schemaObject);
110
+ }
111
+ function getComponentsSimpleMetadata() {
112
+ return componentList
113
+ .map((component) => {
114
+ const context = `
115
+ ------------------------------------------------------------
116
+ 组件名称:${component.name}
117
+ 组件Id:${component.id}
118
+ 组件描述(适用场景):${component.description}
119
+ ------------------------------------------------------------
120
+ `;
121
+ return context;
122
+ })
123
+ .filter(Boolean)
124
+ .join('\n');
125
+ }
126
+ function getComponentsMetadata() {
127
+ return componentList
128
+ .map((component) => {
129
+ const context = `
130
+ ------------------------------------------------------------
131
+ 组件名称:${component.name}
132
+ 组件Id:${component.id}
133
+ 组件描述(适用场景):${component.description}
134
+ 组件属性结构:${JSON.stringify((0, zod_utils_1.zodSchemaToJsonSchema)(component.properties))}
135
+ ------------------------------------------------------------
136
+ `;
137
+ return context;
138
+ })
139
+ .filter(Boolean)
140
+ .join('\n');
141
+ }
@@ -3,3 +3,26 @@
3
3
  * and generating a list of all HTML files in each subfolder
4
4
  */
5
5
  export declare function updateFileList(): Promise<void>;
6
+ /**
7
+ * File content information interface
8
+ */
9
+ export interface FileContent {
10
+ filePath: string;
11
+ fileName: string;
12
+ content: string;
13
+ }
14
+ /**
15
+ * Recursively reads files matching a pattern from a directory and its subdirectories
16
+ * @param dirPath - The directory path to search in
17
+ * @param pattern - String or RegExp pattern to match file names
18
+ * @param options - Optional configuration
19
+ * @returns Promise<FileContent[]> - Array of file content objects
20
+ */
21
+ export declare function readFilesByPattern(dirPath: string, pattern: string | RegExp, options?: {
22
+ recursive?: boolean;
23
+ }): Promise<FileContent[]>;
24
+ export declare function readFileByPath(filePath: string): Promise<string>;
25
+ /**
26
+ * Save content to a file, creating directories if needed
27
+ */
28
+ export declare function saveFileByPath(filePath: string, content: string): Promise<void>;
@@ -27,6 +27,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.updateFileList = updateFileList;
30
+ exports.readFilesByPattern = readFilesByPattern;
31
+ exports.readFileByPath = readFileByPath;
32
+ exports.saveFileByPath = saveFileByPath;
30
33
  const fs_1 = require("fs");
31
34
  const fs = __importStar(require("fs/promises"));
32
35
  const path_1 = __importDefault(require("path"));
@@ -132,3 +135,77 @@ const FILE_LIST_DATA = [];`);
132
135
  console.error('Error updating file list:', error);
133
136
  }
134
137
  }
138
+ /**
139
+ * Recursively reads files matching a pattern from a directory and its subdirectories
140
+ * @param dirPath - The directory path to search in
141
+ * @param pattern - String or RegExp pattern to match file names
142
+ * @param options - Optional configuration
143
+ * @returns Promise<FileContent[]> - Array of file content objects
144
+ */
145
+ async function readFilesByPattern(dirPath, pattern, options = { recursive: true }) {
146
+ const results = [];
147
+ // Convert string pattern to RegExp if needed
148
+ const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
149
+ /**
150
+ * Recursively process directory
151
+ */
152
+ async function processDirectory(currentPath) {
153
+ try {
154
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
155
+ for (const entry of entries) {
156
+ const fullPath = path_1.default.join(currentPath, entry.name);
157
+ if (entry.isDirectory() && options.recursive) {
158
+ // Recursively process subdirectory
159
+ await processDirectory(fullPath);
160
+ }
161
+ else if (entry.isFile() && regex.test(entry.name)) {
162
+ // Read file content if it matches the pattern
163
+ try {
164
+ const content = await fs.readFile(fullPath, 'utf8');
165
+ results.push({
166
+ filePath: fullPath,
167
+ fileName: entry.name,
168
+ content,
169
+ });
170
+ }
171
+ catch (fileError) {
172
+ // Ignore individual file read errors and continue
173
+ console.warn(`Warning: Failed to read file ${fullPath}:`, fileError);
174
+ }
175
+ }
176
+ }
177
+ }
178
+ catch (dirError) {
179
+ // Ignore directory read errors and continue
180
+ console.warn(`Warning: Failed to read directory ${currentPath}:`, dirError);
181
+ }
182
+ }
183
+ // Check if the directory exists before processing
184
+ if (!(0, fs_1.existsSync)(dirPath)) {
185
+ console.warn(`Warning: Directory ${dirPath} does not exist`);
186
+ return results;
187
+ }
188
+ await processDirectory(dirPath);
189
+ return results;
190
+ }
191
+ // 读取文件内容
192
+ async function readFileByPath(filePath) {
193
+ try {
194
+ const absolutePath = path_1.default.resolve(process.cwd(), filePath);
195
+ const content = await fs.readFile(absolutePath, 'utf-8');
196
+ return content;
197
+ }
198
+ catch (error) {
199
+ throw new Error(`无法读取文件 "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
200
+ }
201
+ }
202
+ /**
203
+ * Save content to a file, creating directories if needed
204
+ */
205
+ async function saveFileByPath(filePath, content) {
206
+ const pathModule = await Promise.resolve().then(() => __importStar(require('path')));
207
+ const fsModule = await Promise.resolve().then(() => __importStar(require('fs/promises')));
208
+ const dir = pathModule.dirname(filePath);
209
+ await fsModule.mkdir(dir, { recursive: true });
210
+ await fsModule.writeFile(filePath, content, 'utf8');
211
+ }
@@ -0,0 +1,16 @@
1
+ import { Agent, type AgentInvokeOptions, type AgentOptions, type AgentProcessResult, type Message } from '@aigne/core';
2
+ import type { PromiseOrValue } from '@aigne/core/utils/type-utils.js';
3
+ export interface ReflectionAgentOptions<I extends Message = Message, RO extends Message = Message> extends AgentOptions<I, I> {
4
+ editor: Agent<I, I>;
5
+ reviewer: Agent<I, RO>;
6
+ isApproved?: (result: RO) => PromiseOrValue<boolean>;
7
+ maxIterations?: number;
8
+ }
9
+ export declare class ReflectionAgent<I extends Message = Message, RO extends Message = Message> extends Agent<I, I> {
10
+ constructor(options: ReflectionAgentOptions<I, RO>);
11
+ editor: Agent<I, I>;
12
+ reviewer: Agent<I, RO>;
13
+ isApproved?: (result: RO) => PromiseOrValue<boolean>;
14
+ maxIterations: number;
15
+ process(input: I, options: AgentInvokeOptions): Promise<AgentProcessResult<I>>;
16
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReflectionAgent = void 0;
4
+ const core_1 = require("@aigne/core");
5
+ const DEFAULT_MAX_ITERATIONS = 3;
6
+ class ReflectionAgent extends core_1.Agent {
7
+ constructor(options) {
8
+ super(options);
9
+ this.editor = options.editor;
10
+ this.reviewer = options.reviewer;
11
+ this.isApproved = options.isApproved;
12
+ this.maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
13
+ }
14
+ editor;
15
+ reviewer;
16
+ isApproved;
17
+ maxIterations;
18
+ async process(input, options) {
19
+ let previousResult = input;
20
+ let reviewResult;
21
+ let iterations = 0;
22
+ // 先执行一次 editor,确保有结果
23
+ previousResult = await options.context.invoke(this.editor, previousResult);
24
+ do {
25
+ reviewResult = await options.context.invoke(this.reviewer, previousResult);
26
+ const isApproved = await this.isApproved?.(reviewResult);
27
+ if (isApproved === true) {
28
+ return previousResult;
29
+ }
30
+ previousResult = await options.context.invoke(this.editor, {
31
+ ...previousResult,
32
+ ...reviewResult,
33
+ });
34
+ } while (++iterations < this.maxIterations);
35
+ return previousResult;
36
+ }
37
+ }
38
+ exports.ReflectionAgent = ReflectionAgent;
@@ -0,0 +1,13 @@
1
+ import { AIAgent } from '@aigne/core';
2
+ /**
3
+ * 用于设计页面结构的 workflow
4
+ * 1. AI 根据拿到的 collectorResult 和 componentList,生成一个页面设计模板,需要用 ASCII 图画出来,给到用户确认
5
+ * 2. 用户确认后,AI 保存页面设计模板,并返回页面设计模板
6
+ */
7
+ export declare const designerAgent: AIAgent<{
8
+ collectResult: string;
9
+ }, {
10
+ ascii: string;
11
+ $message: string;
12
+ filteredComponentList: string[];
13
+ }>;
@@ -0,0 +1,61 @@
1
+ import { DefaultMemory } from '@aigne/agent-library/default-memory/index.js';
2
+ import { AIAgent } from '@aigne/core';
3
+ import assert from 'node:assert';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { z } from 'zod';
7
+ const { OPENAI_API_KEY } = process.env;
8
+ assert(OPENAI_API_KEY, 'Please set the OPENAI_API_KEY environment variable');
9
+ const memory = new DefaultMemory({
10
+ storage: {
11
+ url: 'file:./dbs/memory.db', // Path to store memory data, such as 'file:./memory.db'
12
+ },
13
+ });
14
+ const componentList = fs.readFileSync(path.join(__dirname, '../data-sources/pages-kit-component-list.yaml'), 'utf-8');
15
+ const agentInstructions = `
16
+ 你是一个专业的页面设计师,名叫小设。你的任务是根据整理好的用户需求,设计一个页面结构。
17
+
18
+ 设计规则:
19
+ 1. 设计的页面结构,需要画出 ASCII 图,给到用户确认
20
+ 2. 需要在 ASCII 图上,标注出结构和放什么内容
21
+ 3. 需要在限定的组件列表中,选择合适的组件
22
+ 4. 具有把拼装复合组件的能力,如果涉及到复合组件,请将他们框选起来,标注出复合组件的结构
23
+ 5. 不用告诉用户这是 ASCII 图,用户不关心,用户只关心页面设计模板
24
+ 6. 你只能使用支持的组件列表中的组件,不能使用其他组件
25
+ 7. 如果在没有找到合适的组件,请使用拼装组件的能力,将多个组件拼装起来,形成一个复合组件
26
+
27
+
28
+ 支持使用的组件列表:
29
+ <component-list>
30
+ ${componentList}
31
+ </component-list>
32
+
33
+ 整理好的用户需求:
34
+ <collect-result>
35
+ {{collectResult}}
36
+ </collect-result>
37
+
38
+ 用户反馈:
39
+ <<< {{userFeedBack}} >>>
40
+ `;
41
+ /**
42
+ * 用于设计页面结构的 workflow
43
+ * 1. AI 根据拿到的 collectorResult 和 componentList,生成一个页面设计模板,需要用 ASCII 图画出来,给到用户确认
44
+ * 2. 用户确认后,AI 保存页面设计模板,并返回页面设计模板
45
+ */
46
+ export const designerAgent = AIAgent.from({
47
+ name: 'designer',
48
+ description: '设计页面结构,并且给到用户确认',
49
+ inputSchema: z.object({
50
+ collectResult: z.string().describe('整理好的用户需求'),
51
+ }),
52
+ outputSchema: z.object({
53
+ ascii: z.string().describe('ASCII 图'),
54
+ $message: z.string().describe('给到用户的信息,用于用户确认,不需要包含 ASCII 图'),
55
+ filteredComponentList: z.array(z.string()).describe('过滤后的组件列表,只包含页面设计需要的组件'),
56
+ }),
57
+ memory,
58
+ instructions: `
59
+ ${agentInstructions}
60
+ `,
61
+ });
@@ -0,0 +1,18 @@
1
+ import { FunctionAgent } from '@aigne/core';
2
+ import { ReflectionAgent } from '../workflow-agents/reflection-agent.js';
3
+ export declare const generatorAgentWithReflection: ReflectionAgent<{
4
+ ascii: string;
5
+ collectResult: string;
6
+ $message: string;
7
+ filteredComponentList: string[];
8
+ feedback?: string | null | undefined;
9
+ }, {
10
+ isApproved: boolean;
11
+ feedback: string;
12
+ }>;
13
+ export declare const saveYamlAgent: FunctionAgent<{
14
+ $message: string;
15
+ yaml: string;
16
+ }, {
17
+ $message: string;
18
+ } & import("@aigne/core").Message>;
@@ -0,0 +1,180 @@
1
+ import { DefaultMemory } from '@aigne/agent-library/default-memory/index.js';
2
+ import { AIAgent, FunctionAgent, createMessage } from '@aigne/core';
3
+ import assert from 'node:assert';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { z } from 'zod';
7
+ import { ReflectionAgent } from '../workflow-agents/reflection-agent.js';
8
+ const { OPENAI_API_KEY } = process.env;
9
+ assert(OPENAI_API_KEY, 'Please set the OPENAI_API_KEY environment variable');
10
+ const memory = new DefaultMemory({
11
+ storage: {
12
+ url: 'file:./dbs/memory.db', // Path to store memory data, such as 'file:./memory.db'
13
+ },
14
+ });
15
+ const componentList = fs.readFileSync(path.join(__dirname, '../data-sources/pages-kit-component-list.yaml'), 'utf-8');
16
+ const pagesKitTemplateRule = fs.readFileSync(path.join(__dirname, '../data-sources/pages-kit-template-rule.md'), 'utf-8');
17
+ const generatorAgentInstructions = `
18
+ 你是专业的 Pages Kit 模板工程师小猿。你的任务是根据用户需求和设计师的页面设计模板,生成完全符合 Pages Kit 框架规范的 YAML 结构。
19
+
20
+ ## 核心职责
21
+ 基于提供的用户需求、设计师ASCII图和组件列表,生成可直接使用的 Pages Kit YAML 模板。
22
+
23
+ ## 严格遵循的编码原则
24
+ 1. **结构完整性**: 必须完全符合 Pages Kit 框架的 YAML Schema 结构规范
25
+ 2. **设计一致性**: 严格按照设计师的页面设计模板实现,不得擅自修改布局和结构
26
+ 3. **组件组合**: 当单个组件无法满足设计需求时,使用多个组件组合实现复杂布局
27
+ 4. **ID唯一性**: 所有涉及 id 的属性值必须唯一,使用16位随机字符串(字母+数字混合,无语义化)
28
+ 5. **语义准确性**: 确保组件选择和属性配置准确反映用户需求和设计意图
29
+
30
+ ## 输出要求
31
+ - 生成完整可执行的 YAML 结构
32
+ - 在 $message 中简洑说明实现思路和关键设计决策
33
+ - 确保所有组件都来自提供的过滤组件列表
34
+ - 必须返回所有输入字段以保持数据流的完整性
35
+
36
+ ## 技术规范参考
37
+ <pages-kit-template-rule>
38
+ ${pagesKitTemplateRule}
39
+ </pages-kit-template-rule>
40
+
41
+ ## 全部可用组件
42
+ <component-list>
43
+ ${componentList}
44
+ </component-list>
45
+
46
+ ## 当前任务输入
47
+ 用户需求:
48
+ <collect-result>
49
+ {{collectResult}}
50
+ </collect-result>
51
+
52
+ 设计师页面模板:
53
+ <ascii>
54
+ {{ascii}}
55
+ </ascii>
56
+
57
+ 本次可使用的组件(已过滤):
58
+ <filtered-component-list>
59
+ {{filteredComponentList}}
60
+ </filtered-component-list>
61
+
62
+ <#if feedback>
63
+ ## 验证反馈
64
+ 上一次生成的YAML结构存在以下问题,请根据反馈进行修正:
65
+ <feedback>
66
+ {{feedback}}
67
+ </feedback>
68
+ </#if>
69
+
70
+ <#if yaml>
71
+ ## 上一次生成的YAML结构
72
+ <yaml>
73
+ {{yaml}}
74
+ </yaml>
75
+ </#if>
76
+
77
+ 请严格按照上述要求生成YAML结构,并确保返回所有必需的字段。`;
78
+ const validatorAgentInstructions = `
79
+ 你是专业的 Pages Kit 模板验证专家小验。你的任务是严格验证生成的 YAML 结构是否完全符合 Pages Kit 框架规范。
80
+
81
+ ## 核心职责
82
+ 对生成的 YAML 模板进行全面技术验证,确保其在 Pages Kit 框架中能够正确运行。
83
+
84
+ ## 验证检查清单
85
+ 1. **结构规范性**: 严格检查是否完全符合 Pages Kit 框架的 YAML Schema 结构
86
+ 2. **语法正确性**: 验证 YAML 语法格式是否正确,缩进、字段名等是否准确
87
+ 3. **ID唯一性**: 所有 id 属性值必须唯一且为16位随机字符串(字母数字混合,非语义化)
88
+ 4. **组件合法性**: 确认所有使用的组件都在允许的组件列表中
89
+ 5. **属性完整性**: 检查必需属性是否全部提供,可选属性是否合理
90
+ 6. **嵌套层级**: 验证嵌套结构深度和层级关系是否正确
91
+ 7. **数据类型**: 确认各字段的数据类型符合规范要求
92
+
93
+ ## 技术规范依据
94
+ <pages-kit-template-rule>
95
+ ${pagesKitTemplateRule}
96
+ </pages-kit-template-rule>
97
+
98
+ ## 验证输入
99
+ 用户需求:{{collectResult}}
100
+ 设计师ASCII图:{{ascii}}
101
+ 可用组件列表:{{filteredComponentList}}
102
+ 生成的YAML:{{yaml}}
103
+
104
+ ## 验证原则
105
+ - 零容忍态度对待规范违规
106
+ - 优先保证模板的可执行性和稳定性
107
+ - 发现问题时提供清晰的改进建议
108
+
109
+ 请对提供的 YAML 结构进行全面验证。`;
110
+ /**
111
+ * 用于实现页面结构的 workflow
112
+ * 1. AI 根据拿到的 ASCII 图,整理好的用户需求,支持使用的组件列表,生成一个 Yaml 结构,给到验证器验证
113
+ * 2. 使用反思工作流,AI 自动根据验证器反馈,自动修改 Yaml 结构,直到验证器验证通过
114
+ * 3. 验证器验证通过后,AI 保存 Yaml 结构,并返回 Yaml 结构
115
+ */
116
+ const generatorAgent = AIAgent.from({
117
+ name: 'generator',
118
+ description: '实现页面结构,并且给到用户确认',
119
+ inputSchema: z.object({
120
+ ascii: z.string().describe('ASCII 图'),
121
+ collectResult: z.string().describe('整理好的用户需求'),
122
+ filteredComponentList: z.array(z.string()).describe('过滤后的组件列表,只包含页面设计需要的组件'),
123
+ $message: z.string(),
124
+ feedback: z.string().nullish().describe('Feedback from the reviewer'),
125
+ }),
126
+ outputSchema: z.object({
127
+ ascii: z.string().describe('ASCII 图'),
128
+ collectResult: z.string().describe('整理好的用户需求'),
129
+ filteredComponentList: z.array(z.string()).describe('过滤后的组件列表,只包含页面设计需要的组件'),
130
+ $message: z.string().describe('给到用户的信息,用于用户确认'),
131
+ yaml: z.string().describe('Yaml 结构'),
132
+ feedback: z.string().nullish().describe('Feedback from the reviewer'),
133
+ }),
134
+ memory,
135
+ instructions: `
136
+ ${generatorAgentInstructions}
137
+ `,
138
+ });
139
+ const validatorAgent = AIAgent.from({
140
+ name: 'validator',
141
+ description: '验证 Yaml 结构符合 Pages Kit 框架的 Yaml Schema 结构',
142
+ inputSchema: z.object({
143
+ ascii: z.string().describe('ASCII 图'),
144
+ collectResult: z.string().describe('整理好的用户需求'),
145
+ filteredComponentList: z.array(z.string()).describe('过滤后的组件列表,只包含页面设计需要的组件'),
146
+ $message: z.string(),
147
+ yaml: z.string().describe('Yaml 结构'),
148
+ feedback: z.string().nullish().describe('Feedback from the reviewer'),
149
+ }),
150
+ memory,
151
+ outputSchema: z.object({
152
+ isApproved: z.boolean().describe('是否符合 Pages Kit 框架的 Yaml Schema 结构'),
153
+ feedback: z.string().describe('Feedback for the markdown'),
154
+ }),
155
+ instructions: `
156
+ ${validatorAgentInstructions}
157
+ `,
158
+ });
159
+ export const generatorAgentWithReflection = new ReflectionAgent({
160
+ name: 'generator-with-reflection',
161
+ maxIterations: 3,
162
+ editor: generatorAgent,
163
+ reviewer: validatorAgent,
164
+ isApproved: (result) => result.isApproved,
165
+ });
166
+ export const saveYamlAgent = FunctionAgent.from({
167
+ inputSchema: z.object({
168
+ $message: z.string().describe('给到用户的信息,用于用户确认'),
169
+ yaml: z.string().describe('Yaml 结构'),
170
+ }),
171
+ name: 'save-yaml',
172
+ description: '保存 Yaml 结构到文件',
173
+ async process({ yaml }) {
174
+ const templateName = new Date().toISOString().replace(/[:.]/g, '-');
175
+ const filePath = path.join(__dirname, `../test-templates/template-${templateName}.yaml`);
176
+ // 把 yaml 结构保存到文件
177
+ fs.writeFileSync(filePath, yaml);
178
+ return createMessage(`Yaml 结构已保存到 ${filePath}`);
179
+ },
180
+ });