@louloulinx/metagpt 0.1.3

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 (113) hide show
  1. package/.eslintrc.json +23 -0
  2. package/.prettierrc +7 -0
  3. package/LICENSE +21 -0
  4. package/README-CN.md +754 -0
  5. package/README.md +238 -0
  6. package/bun.lock +1023 -0
  7. package/doc/TutorialAssistant.md +114 -0
  8. package/doc/VercelLLMProvider.md +164 -0
  9. package/eslint.config.js +55 -0
  10. package/examples/data-interpreter-example.ts +173 -0
  11. package/examples/qwen-direct-example.ts +60 -0
  12. package/examples/qwen-example.ts +62 -0
  13. package/examples/tutorial-assistant-example.ts +97 -0
  14. package/jest.config.ts +22 -0
  15. package/output/tutorials/Go/350/257/255/350/250/200/347/274/226/347/250/213/346/225/231/347/250/213_2025-02-25T09-35-15-436Z.md +2208 -0
  16. package/output/tutorials/Rust/346/225/231/347/250/213_2025-02-25T08-27-27-632Z.md +1967 -0
  17. package/output/tutorials//345/246/202/344/275/225/344/275/277/347/224/250TypeScript/345/274/200/345/217/221Node.js/345/272/224/347/224/250_2025-02-25T08-14-39-605Z.md +1721 -0
  18. package/output/tutorials//346/225/260/345/255/227/347/273/217/346/265/216/345/255/246/346/225/231/347/250/213_2025-02-25T10-45-03-605Z.md +902 -0
  19. package/output/tutorials//346/232/250/345/215/227/345/244/247/345/255/246/346/225/260/345/255/227/347/273/217/346/265/216/345/255/246/345/244/215/350/257/225/350/265/204/346/226/231_2025-02-25T11-16-59-133Z.md +719 -0
  20. package/package.json +58 -0
  21. package/plan-cn.md +321 -0
  22. package/plan.md +154 -0
  23. package/src/actions/analyze-task.ts +65 -0
  24. package/src/actions/base-action.ts +103 -0
  25. package/src/actions/di/execute-nb-code.ts +247 -0
  26. package/src/actions/di/write-analysis-code.ts +234 -0
  27. package/src/actions/write-tutorial.ts +232 -0
  28. package/src/config/browser.ts +33 -0
  29. package/src/config/config.ts +345 -0
  30. package/src/config/embedding.ts +26 -0
  31. package/src/config/llm.ts +36 -0
  32. package/src/config/mermaid.ts +37 -0
  33. package/src/config/omniparse.ts +25 -0
  34. package/src/config/redis.ts +34 -0
  35. package/src/config/s3.ts +33 -0
  36. package/src/config/search.ts +30 -0
  37. package/src/config/workspace.ts +20 -0
  38. package/src/index.ts +40 -0
  39. package/src/management/team.ts +168 -0
  40. package/src/memory/longterm.ts +218 -0
  41. package/src/memory/manager.ts +160 -0
  42. package/src/memory/types.ts +100 -0
  43. package/src/memory/working.ts +154 -0
  44. package/src/monitoring/system.ts +413 -0
  45. package/src/monitoring/types.ts +230 -0
  46. package/src/plugin/manager.ts +79 -0
  47. package/src/plugin/types.ts +114 -0
  48. package/src/provider/vercel-llm.ts +314 -0
  49. package/src/rag/base-rag.ts +194 -0
  50. package/src/rag/document-qa.ts +102 -0
  51. package/src/roles/base-role.ts +155 -0
  52. package/src/roles/data-interpreter.ts +360 -0
  53. package/src/roles/engineer.ts +1 -0
  54. package/src/roles/tutorial-assistant.ts +217 -0
  55. package/src/skills/base-skill.ts +144 -0
  56. package/src/skills/code-review.ts +120 -0
  57. package/src/tools/base-tool.ts +155 -0
  58. package/src/tools/file-system.ts +204 -0
  59. package/src/tools/tool-recommend.d.ts +14 -0
  60. package/src/tools/tool-recommend.ts +31 -0
  61. package/src/types/action.ts +38 -0
  62. package/src/types/config.ts +129 -0
  63. package/src/types/document.ts +354 -0
  64. package/src/types/llm.ts +64 -0
  65. package/src/types/memory.ts +36 -0
  66. package/src/types/message.ts +193 -0
  67. package/src/types/rag.ts +86 -0
  68. package/src/types/role.ts +67 -0
  69. package/src/types/skill.ts +71 -0
  70. package/src/types/task.ts +32 -0
  71. package/src/types/team.ts +55 -0
  72. package/src/types/tool.ts +77 -0
  73. package/src/types/workflow.ts +133 -0
  74. package/src/utils/common.ts +73 -0
  75. package/src/utils/yaml.ts +67 -0
  76. package/src/websocket/browser-client.ts +187 -0
  77. package/src/websocket/client.ts +186 -0
  78. package/src/websocket/server.ts +169 -0
  79. package/src/websocket/types.ts +125 -0
  80. package/src/workflow/executor.ts +193 -0
  81. package/src/workflow/executors/action-executor.ts +72 -0
  82. package/src/workflow/executors/condition-executor.ts +118 -0
  83. package/src/workflow/executors/parallel-executor.ts +201 -0
  84. package/src/workflow/executors/role-executor.ts +76 -0
  85. package/src/workflow/executors/sequence-executor.ts +196 -0
  86. package/tests/actions.test.ts +105 -0
  87. package/tests/benchmark/performance.test.ts +147 -0
  88. package/tests/config/config.test.ts +115 -0
  89. package/tests/config.test.ts +106 -0
  90. package/tests/e2e/setup.ts +74 -0
  91. package/tests/e2e/workflow.test.ts +88 -0
  92. package/tests/llm.test.ts +84 -0
  93. package/tests/memory/memory.test.ts +164 -0
  94. package/tests/memory.test.ts +63 -0
  95. package/tests/monitoring/monitoring.test.ts +225 -0
  96. package/tests/plugin/plugin.test.ts +183 -0
  97. package/tests/provider/bailian-llm.test.ts +98 -0
  98. package/tests/rag.test.ts +162 -0
  99. package/tests/roles.test.ts +88 -0
  100. package/tests/skills.test.ts +166 -0
  101. package/tests/team.test.ts +143 -0
  102. package/tests/tools.test.ts +170 -0
  103. package/tests/types/document.test.ts +181 -0
  104. package/tests/types/message.test.ts +122 -0
  105. package/tests/utils/yaml.test.ts +110 -0
  106. package/tests/utils.test.ts +74 -0
  107. package/tests/websocket/browser-client.test.ts +1 -0
  108. package/tests/websocket/websocket.test.ts +42 -0
  109. package/tests/workflow/parallel-executor.test.ts +224 -0
  110. package/tests/workflow/sequence-executor.test.ts +207 -0
  111. package/tests/workflow.test.ts +290 -0
  112. package/tsconfig.json +27 -0
  113. package/typedoc.json +25 -0
@@ -0,0 +1,217 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ import { BaseRole } from './base-role';
5
+ import { WriteDirectory, WriteContent } from '../actions/write-tutorial';
6
+ import type { Directory } from '../actions/write-tutorial';
7
+ import type { Message, MESSAGE_ROUTE } from '../types/message';
8
+ import type { LLMProvider } from '../types/llm';
9
+
10
+ /**
11
+ * 教程助手配置接口
12
+ */
13
+ export interface TutorialAssistantConfig {
14
+ llm: LLMProvider;
15
+ language?: string;
16
+ outputDir?: string;
17
+ }
18
+
19
+ /**
20
+ * 教程助手,输入一个句子生成Markdown格式的教程文档
21
+ */
22
+ export class TutorialAssistant extends BaseRole {
23
+ language: string;
24
+ outputDir: string;
25
+ llm: LLMProvider;
26
+
27
+ topic = '';
28
+ mainTitle = '';
29
+ totalContent = '';
30
+
31
+ constructor(config: TutorialAssistantConfig) {
32
+ super(
33
+ 'Stitch',
34
+ 'Tutorial Assistant',
35
+ 'Generate tutorial documents',
36
+ 'Strictly follow Markdown\'s syntax, with neat and standardized layout',
37
+ []
38
+ );
39
+
40
+ console.log('[TutorialAssistant] Initializing with config:', {
41
+ language: config.language || 'Chinese',
42
+ outputDir: config.outputDir || path.join(process.cwd(), 'tutorials')
43
+ });
44
+
45
+ this.language = config.language || 'Chinese';
46
+ this.outputDir = config.outputDir || path.join(process.cwd(), 'tutorials');
47
+ this.llm = config.llm;
48
+
49
+ // 初始化动作
50
+ this.initializeActions();
51
+ }
52
+
53
+ /**
54
+ * 初始化动作列表
55
+ */
56
+ private initializeActions(): void {
57
+ console.log('[TutorialAssistant] Initializing actions');
58
+
59
+ // 初始时只设置目录生成动作
60
+ const writeDirectory = new WriteDirectory({
61
+ llm: this.llm,
62
+ language: this.language,
63
+ });
64
+
65
+ console.log('[TutorialAssistant] Created WriteDirectory action');
66
+ this.actions = [writeDirectory];
67
+ }
68
+
69
+ /**
70
+ * 处理目录结构
71
+ * @param directory 目录结构
72
+ */
73
+ private async handleDirectory(directory: Directory): Promise<void> {
74
+ console.log('[TutorialAssistant] Handling directory structure:', JSON.stringify(directory, null, 2));
75
+
76
+ this.mainTitle = directory.title;
77
+ this.totalContent += `# ${this.mainTitle}\n\n`;
78
+
79
+ // 将所有章节内容生成动作添加到动作列表
80
+ const actions = [...this.actions];
81
+
82
+ console.log(`[TutorialAssistant] Processing ${directory.directory.length} sections`);
83
+
84
+ for (const section of directory.directory) {
85
+ const sectionKey = Object.keys(section)[0];
86
+ console.log(`[TutorialAssistant] Creating WriteContent action for section: ${sectionKey}`);
87
+
88
+ const writeContent = new WriteContent({
89
+ llm: this.llm,
90
+ language: this.language,
91
+ directory: section,
92
+ });
93
+
94
+ actions.push(writeContent);
95
+ }
96
+
97
+ console.log(`[TutorialAssistant] Updated actions list, now contains ${actions.length} actions`);
98
+ this.actions = actions;
99
+ }
100
+
101
+ /**
102
+ * 处理消息
103
+ * @param message 输入消息
104
+ * @returns 处理结果
105
+ */
106
+ async react(message: Message): Promise<Message> {
107
+ console.log('[TutorialAssistant] Starting react method with message:', message.content);
108
+
109
+ try {
110
+ // 保存主题
111
+ this.topic = message.content;
112
+ console.log(`[TutorialAssistant] Set topic: "${this.topic}"`);
113
+
114
+ // 执行所有动作
115
+ console.log(`[TutorialAssistant] Starting execution of ${this.actions.length} actions`);
116
+
117
+ for (let i = 0; i < this.actions.length; i++) {
118
+ const action = this.actions[i];
119
+ console.log(`[TutorialAssistant] Running action ${i+1}/${this.actions.length}: ${action.constructor.name}`);
120
+
121
+ // 为动作设置主题参数
122
+ if ('setArg' in action && typeof action.setArg === 'function') {
123
+ console.log(`[TutorialAssistant] Setting topic argument for action: "${this.topic}"`);
124
+ action.setArg('topic', this.topic);
125
+ }
126
+
127
+ // 执行动作
128
+ console.log(`[TutorialAssistant] Executing action ${action.constructor.name}`);
129
+ const result = await action.run();
130
+ console.log(`[TutorialAssistant] Action ${action.constructor.name} completed with status: ${result.status}`);
131
+
132
+ if (result.status === 'failed') {
133
+ console.error(`[TutorialAssistant] Action failed: ${result.content}`);
134
+ return this.createMessage(`Failed to generate tutorial: ${result.content}`);
135
+ }
136
+
137
+ // 处理目录生成结果
138
+ if (action instanceof WriteDirectory) {
139
+ console.log('[TutorialAssistant] Processing WriteDirectory result');
140
+ if (result.instructContent) {
141
+ console.log('[TutorialAssistant] Directory structure generated, handling it');
142
+ await this.handleDirectory(result.instructContent as Directory);
143
+ } else {
144
+ console.warn('[TutorialAssistant] WriteDirectory action did not produce instructContent');
145
+ }
146
+ }
147
+ // 处理内容生成结果
148
+ else if (action instanceof WriteContent) {
149
+ console.log('[TutorialAssistant] Processing WriteContent result');
150
+ if (this.totalContent.length > 0) {
151
+ this.totalContent += '\n\n\n';
152
+ }
153
+ console.log(`[TutorialAssistant] Adding content (${result.content.length} characters)`);
154
+ this.totalContent += result.content;
155
+ }
156
+ }
157
+
158
+ // 保存生成的内容到文件
159
+ console.log('[TutorialAssistant] All actions completed, saving content to file');
160
+ const filePath = await this.saveToFile();
161
+ console.log(`[TutorialAssistant] Content saved to ${filePath}`);
162
+
163
+ return this.createMessage(`Tutorial generated successfully and saved to ${filePath}`);
164
+ } catch (error) {
165
+ console.error('[TutorialAssistant] Error in react method:', error);
166
+ return this.createMessage(`Error generating tutorial: ${error}`);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * 创建消息对象
172
+ * @param content 消息内容
173
+ * @returns 消息对象
174
+ */
175
+ private createMessage(content: string): Message {
176
+ console.log(`[TutorialAssistant] Creating message: ${content}`);
177
+ return {
178
+ id: uuidv4(),
179
+ content,
180
+ role: this.profile,
181
+ causedBy: 'TutorialAssistant',
182
+ sentFrom: this.name,
183
+ sendTo: new Set(['*']),
184
+ instructContent: null,
185
+ };
186
+ }
187
+
188
+ /**
189
+ * 保存内容到文件
190
+ * @returns 文件路径
191
+ */
192
+ private async saveToFile(): Promise<string> {
193
+ try {
194
+ console.log(`[TutorialAssistant] Saving content (${this.totalContent.length} characters) to file`);
195
+
196
+ // 确保输出目录存在
197
+ console.log(`[TutorialAssistant] Creating output directory: ${this.outputDir}`);
198
+ await fs.mkdir(this.outputDir, { recursive: true });
199
+
200
+ // 生成带时间戳的文件名
201
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
202
+ const fileName = `${this.mainTitle || 'Tutorial'}_${timestamp}.md`;
203
+ const filePath = path.join(this.outputDir, fileName);
204
+
205
+ console.log(`[TutorialAssistant] Writing to file: ${filePath}`);
206
+
207
+ // 写入文件
208
+ await fs.writeFile(filePath, this.totalContent);
209
+ console.log(`[TutorialAssistant] File written successfully: ${filePath}`);
210
+
211
+ return filePath;
212
+ } catch (error) {
213
+ console.error('[TutorialAssistant] Error saving tutorial file:', error);
214
+ throw error;
215
+ }
216
+ }
217
+ }
@@ -0,0 +1,144 @@
1
+ import { z } from 'zod';
2
+ import type { Skill, SkillConfig, SkillContext, SkillResult } from '../types/skill';
3
+ import type { Action } from '../types/action';
4
+ import type { LLMProvider } from '../types/llm';
5
+ import { SkillContextSchema, SkillResultSchema } from '../types/skill';
6
+
7
+ /**
8
+ * 技能基类
9
+ * 提供技能系统的基础功能实现
10
+ */
11
+ export abstract class BaseSkill implements Skill {
12
+ name: string;
13
+ description: string;
14
+ context: SkillContext;
15
+ llm: LLMProvider;
16
+ actions: Action[];
17
+
18
+ constructor(config: SkillConfig) {
19
+ // 验证配置
20
+ const validConfig = z.object({
21
+ name: z.string(),
22
+ description: z.string(),
23
+ llm: z.any(),
24
+ actions: z.array(z.any()).optional(),
25
+ args: z.record(z.any()).optional(),
26
+ }).parse(config);
27
+
28
+ this.name = validConfig.name;
29
+ this.description = validConfig.description;
30
+ this.llm = validConfig.llm;
31
+ this.actions = validConfig.actions || [];
32
+
33
+ // 构建上下文
34
+ this.context = SkillContextSchema.parse({
35
+ name: validConfig.name,
36
+ description: validConfig.description,
37
+ actions: this.actions,
38
+ args: validConfig.args || {},
39
+ llm: validConfig.llm,
40
+ });
41
+ }
42
+
43
+ /**
44
+ * 执行技能
45
+ * 子类必须实现此方法
46
+ */
47
+ abstract execute(args?: Record<string, any>): Promise<SkillResult>;
48
+
49
+ /**
50
+ * 验证技能是否可用
51
+ * 子类可以覆盖此方法以提供自定义验证
52
+ */
53
+ async validate(): Promise<boolean> {
54
+ return this.actions.length > 0;
55
+ }
56
+
57
+ /**
58
+ * 处理技能执行异常
59
+ * @param error 错误对象
60
+ */
61
+ async handleError(error: Error): Promise<void> {
62
+ console.error(`Skill ${this.name} failed:`, error);
63
+ // 子类可以覆盖此方法以提供自定义错误处理
64
+ }
65
+
66
+ /**
67
+ * 创建技能执行结果
68
+ * @param success 是否成功
69
+ * @param message 结果消息
70
+ * @param data 结果数据
71
+ * @param error 错误信息
72
+ */
73
+ protected createResult(
74
+ success: boolean,
75
+ message: string,
76
+ data?: any,
77
+ error?: any
78
+ ): SkillResult {
79
+ return SkillResultSchema.parse({
80
+ success,
81
+ message,
82
+ data,
83
+ error,
84
+ });
85
+ }
86
+
87
+ /**
88
+ * 获取技能参数
89
+ * @param key 参数键
90
+ * @returns 参数值
91
+ */
92
+ protected getArg<T>(key: string): T | undefined {
93
+ return this.context.args?.[key] as T;
94
+ }
95
+
96
+ /**
97
+ * 设置技能参数
98
+ * @param key 参数键
99
+ * @param value 参数值
100
+ */
101
+ protected setArg<T>(key: string, value: T): void {
102
+ if (!this.context.args) {
103
+ this.context.args = {};
104
+ }
105
+ this.context.args[key] = value;
106
+ }
107
+
108
+ /**
109
+ * 执行动作序列
110
+ * @param actions 要执行的动作
111
+ * @returns 执行结果
112
+ */
113
+ protected async executeActions(actions: Action[]): Promise<SkillResult> {
114
+ try {
115
+ const results = [];
116
+ for (const action of actions) {
117
+ const result = await action.run();
118
+ results.push(result);
119
+
120
+ if (result.status === 'failed') {
121
+ return this.createResult(
122
+ false,
123
+ `Action ${action.name} failed: ${result.content}`,
124
+ results
125
+ );
126
+ }
127
+ }
128
+
129
+ return this.createResult(
130
+ true,
131
+ 'All actions completed successfully',
132
+ results
133
+ );
134
+ } catch (error) {
135
+ await this.handleError(error as Error);
136
+ return this.createResult(
137
+ false,
138
+ `Failed to execute actions: ${(error as Error).message}`,
139
+ undefined,
140
+ error
141
+ );
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,120 @@
1
+ import { BaseSkill } from './base-skill';
2
+ import { AnalyzeTask } from '../actions/analyze-task';
3
+ import type { SkillConfig, SkillResult } from '../types/skill';
4
+ import type { ActionOutput } from '../types/action';
5
+
6
+ /**
7
+ * 代码审查技能
8
+ * 使用 LLM 进行代码审查并提供改进建议
9
+ */
10
+ export class CodeReviewSkill extends BaseSkill {
11
+ constructor(config: SkillConfig) {
12
+ super({
13
+ ...config,
14
+ name: 'code_review',
15
+ description: 'Review code and provide improvement suggestions',
16
+ });
17
+
18
+ // 添加代码分析动作
19
+ this.actions.push(
20
+ new AnalyzeTask({
21
+ name: 'analyze_code',
22
+ description: 'Analyze code structure and quality',
23
+ llm: this.llm,
24
+ })
25
+ );
26
+ }
27
+
28
+ /**
29
+ * 执行代码审查
30
+ * @param args 执行参数
31
+ * @returns 审查结果
32
+ */
33
+ async execute(args?: Record<string, any>): Promise<SkillResult> {
34
+ try {
35
+ // 验证输入
36
+ if (!args?.code) {
37
+ return this.createResult(false, 'No code provided for review');
38
+ }
39
+
40
+ // 设置分析参数
41
+ this.actions[0].context.args = {
42
+ task: `Review the following code and provide improvement suggestions:
43
+ ${args.code}
44
+
45
+ Please analyze:
46
+ 1. Code structure and organization
47
+ 2. Potential bugs or issues
48
+ 3. Performance considerations
49
+ 4. Best practices compliance
50
+ 5. Suggested improvements
51
+
52
+ Please provide specific examples and explanations for each point.`,
53
+ };
54
+
55
+ // 执行代码分析
56
+ const result = await this.executeActions(this.actions);
57
+ if (!result.success) {
58
+ return result;
59
+ }
60
+
61
+ // 处理分析结果
62
+ const analysisResults = result.data as ActionOutput[];
63
+ const analysis = analysisResults[0].content;
64
+
65
+ return this.createResult(
66
+ true,
67
+ 'Code review completed successfully',
68
+ {
69
+ analysis,
70
+ suggestions: this.extractSuggestions(analysis),
71
+ }
72
+ );
73
+ } catch (error) {
74
+ await this.handleError(error as Error);
75
+ return this.createResult(
76
+ false,
77
+ `Code review failed: ${(error as Error).message}`,
78
+ undefined,
79
+ error
80
+ );
81
+ }
82
+ }
83
+
84
+ /**
85
+ * 从分析结果中提取建议
86
+ * @param analysis 分析结果文本
87
+ * @returns 建议列表
88
+ */
89
+ private extractSuggestions(analysis: string): string[] {
90
+ const suggestions: string[] = [];
91
+ const lines = analysis.split('\n');
92
+
93
+ let inSuggestionSection = false;
94
+ for (const line of lines) {
95
+ if (line.toLowerCase().includes('suggested improvements')) {
96
+ inSuggestionSection = true;
97
+ continue;
98
+ }
99
+
100
+ if (inSuggestionSection && line.trim()) {
101
+ // 移除序号和点号
102
+ const suggestion = line.replace(/^\d+[.)][ \t]*/, '').trim();
103
+ if (suggestion) {
104
+ suggestions.push(suggestion);
105
+ }
106
+ }
107
+ }
108
+
109
+ return suggestions;
110
+ }
111
+
112
+ /**
113
+ * 自定义错误处理
114
+ */
115
+ async handleError(error: Error): Promise<void> {
116
+ await super.handleError(error);
117
+ this.setArg('lastError', error.message);
118
+ // 可以添加特定的错误处理逻辑,如通知代码作者等
119
+ }
120
+ }
@@ -0,0 +1,155 @@
1
+ import { z } from 'zod';
2
+ import type { Tool, ToolConfig, ToolContext, ToolResult } from '../types/tool';
3
+ import { ToolContextSchema, ToolResultSchema } from '../types/tool';
4
+
5
+ /**
6
+ * 工具基类
7
+ * 提供工具系统的基础功能实现
8
+ */
9
+ export abstract class BaseTool implements Tool {
10
+ name: string;
11
+ description: string;
12
+ version: string;
13
+ category: string;
14
+ context: ToolContext;
15
+
16
+ constructor(config: ToolConfig) {
17
+ // 验证配置
18
+ const validConfig = z.object({
19
+ name: z.string(),
20
+ description: z.string(),
21
+ version: z.string(),
22
+ category: z.string(),
23
+ args: z.record(z.any()).optional(),
24
+ metadata: z.record(z.any()).optional(),
25
+ }).parse(config);
26
+
27
+ this.name = validConfig.name;
28
+ this.description = validConfig.description;
29
+ this.version = validConfig.version;
30
+ this.category = validConfig.category;
31
+
32
+ // 构建上下文
33
+ this.context = ToolContextSchema.parse({
34
+ name: validConfig.name,
35
+ description: validConfig.description,
36
+ args: validConfig.args || {},
37
+ metadata: validConfig.metadata || {},
38
+ state: {},
39
+ });
40
+ }
41
+
42
+ /**
43
+ * 执行工具
44
+ * 子类必须实现此方法
45
+ */
46
+ abstract execute(args?: Record<string, any>): Promise<ToolResult>;
47
+
48
+ /**
49
+ * 验证工具是否可用
50
+ * 子类可以覆盖此方法以提供自定义验证
51
+ */
52
+ async validate(): Promise<boolean> {
53
+ return true;
54
+ }
55
+
56
+ /**
57
+ * 处理工具执行异常
58
+ * @param error 错误对象
59
+ */
60
+ async handleError(error: Error): Promise<void> {
61
+ console.error(`Tool ${this.name} failed:`, error);
62
+ // 子类可以覆盖此方法以提供自定义错误处理
63
+ }
64
+
65
+ /**
66
+ * 获取工具帮助信息
67
+ * 子类可以覆盖此方法以提供更详细的帮助信息
68
+ */
69
+ getHelp(): string {
70
+ return `
71
+ Tool: ${this.name} (v${this.version})
72
+ Category: ${this.category}
73
+ Description: ${this.description}
74
+
75
+ Arguments:
76
+ ${this.formatArgs()}
77
+ `.trim();
78
+ }
79
+
80
+ /**
81
+ * 创建工具执行结果
82
+ * @param success 是否成功
83
+ * @param message 结果消息
84
+ * @param data 结果数据
85
+ * @param error 错误信息
86
+ * @param metadata 结果元数据
87
+ */
88
+ protected createResult(
89
+ success: boolean,
90
+ message: string,
91
+ data?: any,
92
+ error?: any,
93
+ metadata?: Record<string, any>
94
+ ): ToolResult {
95
+ return ToolResultSchema.parse({
96
+ success,
97
+ message,
98
+ data,
99
+ error,
100
+ metadata,
101
+ });
102
+ }
103
+
104
+ /**
105
+ * 获取工具参数
106
+ * @param key 参数键
107
+ * @returns 参数值
108
+ */
109
+ protected getArg<T>(key: string): T | undefined {
110
+ return this.context.args?.[key] as T;
111
+ }
112
+
113
+ /**
114
+ * 设置工具参数
115
+ * @param key 参数键
116
+ * @param value 参数值
117
+ */
118
+ protected setArg<T>(key: string, value: T): void {
119
+ if (!this.context.args) {
120
+ this.context.args = {};
121
+ }
122
+ this.context.args[key] = value;
123
+ }
124
+
125
+ /**
126
+ * 获取工具状态
127
+ * @param key 状态键
128
+ * @returns 状态值
129
+ */
130
+ protected getState<T>(key: string): T | undefined {
131
+ return this.context.state?.[key] as T;
132
+ }
133
+
134
+ /**
135
+ * 设置工具状态
136
+ * @param key 状态键
137
+ * @param value 状态值
138
+ */
139
+ protected setState<T>(key: string, value: T): void {
140
+ if (!this.context.state) {
141
+ this.context.state = {};
142
+ }
143
+ this.context.state[key] = value;
144
+ }
145
+
146
+ /**
147
+ * 格式化参数说明
148
+ */
149
+ private formatArgs(): string {
150
+ const args = this.context.args || {};
151
+ return Object.entries(args)
152
+ .map(([key, value]) => `- ${key}: ${typeof value}`)
153
+ .join('\n');
154
+ }
155
+ }