@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,354 @@
1
+ import { z } from 'zod';
2
+ import path from 'path';
3
+ import fs from 'fs/promises';
4
+
5
+ /**
6
+ * Document status enum, similar to RFC/PEP
7
+ */
8
+ export enum DocumentStatus {
9
+ DRAFT = 'draft',
10
+ UNDERREVIEW = 'underreview',
11
+ APPROVED = 'approved',
12
+ DONE = 'done',
13
+ }
14
+
15
+ /**
16
+ * Base document schema
17
+ */
18
+ export const DocumentSchema = z.object({
19
+ path: z.string().optional(),
20
+ name: z.string().default(''),
21
+ content: z.string().default(''),
22
+ author: z.string().default(''),
23
+ status: z.nativeEnum(DocumentStatus).default(DocumentStatus.DRAFT),
24
+ reviews: z.array(z.any()).default([]),
25
+ });
26
+
27
+ /**
28
+ * Indexable document schema for vector databases or search engines
29
+ */
30
+ export const IndexableDocumentSchema = DocumentSchema.extend({
31
+ data: z.union([z.array(z.any()), z.record(z.string(), z.any())]),
32
+ contentCol: z.string().default(''),
33
+ metaCol: z.string().default(''),
34
+ });
35
+
36
+ /**
37
+ * Repository metadata schema
38
+ */
39
+ export const RepoMetadataSchema = z.object({
40
+ name: z.string().default(''),
41
+ nDocs: z.number().default(0),
42
+ nChars: z.number().default(0),
43
+ symbols: z.array(z.any()).default([]),
44
+ });
45
+
46
+ /**
47
+ * Repository schema
48
+ */
49
+ export const RepoSchema = z.object({
50
+ name: z.string().default(''),
51
+ docs: z.record(z.string(), DocumentSchema).default({}),
52
+ codes: z.record(z.string(), DocumentSchema).default({}),
53
+ assets: z.record(z.string(), DocumentSchema).default({}),
54
+ path: z.string().optional(),
55
+ });
56
+
57
+ /**
58
+ * Document types
59
+ */
60
+ export type Document = z.infer<typeof DocumentSchema> & {
61
+ toPath?: (path?: string) => Promise<void>;
62
+ };
63
+ export type IndexableDocument = z.infer<typeof IndexableDocumentSchema>;
64
+ export type RepoMetadata = z.infer<typeof RepoMetadataSchema>;
65
+ export type Repo = z.infer<typeof RepoSchema>;
66
+
67
+ /**
68
+ * Document class implementation
69
+ */
70
+ export class DocumentImpl implements Document {
71
+ public path?: string;
72
+ public name: string = '';
73
+ public content: string = '';
74
+ public author: string = '';
75
+ public status: DocumentStatus = DocumentStatus.DRAFT;
76
+ public reviews: any[] = [];
77
+
78
+ constructor(data: Partial<Document> = {}) {
79
+ Object.assign(this, DocumentSchema.parse(data));
80
+ }
81
+
82
+ /**
83
+ * Create a Document instance from a file path
84
+ */
85
+ public static async fromPath(filePath: string): Promise<DocumentImpl> {
86
+ try {
87
+ const content = await fs.readFile(filePath, 'utf-8');
88
+ return new DocumentImpl({
89
+ content,
90
+ path: filePath,
91
+ name: path.basename(filePath),
92
+ });
93
+ } catch (error: unknown) {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ throw new Error(`Failed to read file ${filePath}: ${message}`);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Create a Document from a text string
101
+ */
102
+ public static fromText(text: string, filePath?: string): DocumentImpl {
103
+ return new DocumentImpl({
104
+ content: text,
105
+ path: filePath,
106
+ name: filePath ? path.basename(filePath) : '',
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Save content to the specified file path
112
+ */
113
+ public async toPath(filePath?: string): Promise<void> {
114
+ const targetPath = filePath || this.path;
115
+ if (!targetPath) {
116
+ throw new Error('File path is not set.');
117
+ }
118
+
119
+ try {
120
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
121
+ await fs.writeFile(targetPath, this.content, 'utf-8');
122
+ this.path = targetPath;
123
+ } catch (error: unknown) {
124
+ const message = error instanceof Error ? error.message : String(error);
125
+ throw new Error(`Failed to write file ${targetPath}: ${message}`);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Persist document to disk
131
+ */
132
+ public async persist(): Promise<void> {
133
+ return this.toPath();
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Indexable document class implementation
139
+ */
140
+ export class IndexableDocumentImpl extends DocumentImpl implements IndexableDocument {
141
+ public data: any[] | Record<string, any>;
142
+ public contentCol: string = '';
143
+ public metaCol: string = '';
144
+
145
+ constructor(data: Partial<IndexableDocument> = {}) {
146
+ super(data);
147
+ const parsed = IndexableDocumentSchema.parse(data);
148
+ this.data = parsed.data;
149
+ this.contentCol = parsed.contentCol;
150
+ this.metaCol = parsed.metaCol;
151
+ }
152
+
153
+ /**
154
+ * Create an IndexableDocument instance from a file path
155
+ */
156
+ public static async fromPath(
157
+ filePath: string,
158
+ contentCol: string = 'content',
159
+ metaCol: string = 'metadata'
160
+ ): Promise<IndexableDocumentImpl> {
161
+ try {
162
+ const content = await fs.readFile(filePath, 'utf-8');
163
+ let data: any[] | Record<string, any>;
164
+
165
+ // Parse data based on file extension
166
+ const ext = path.extname(filePath).toLowerCase();
167
+ switch (ext) {
168
+ case '.json':
169
+ data = JSON.parse(content);
170
+ break;
171
+ case '.csv':
172
+ // Simple CSV parsing (for more complex needs, use a CSV library)
173
+ data = content.split('\n').map(line => line.split(','));
174
+ break;
175
+ default:
176
+ data = [{ content }];
177
+ }
178
+
179
+ return new IndexableDocumentImpl({
180
+ content,
181
+ path: filePath,
182
+ name: path.basename(filePath),
183
+ data,
184
+ contentCol,
185
+ metaCol,
186
+ });
187
+ } catch (error: unknown) {
188
+ const message = error instanceof Error ? error.message : String(error);
189
+ throw new Error(`Failed to read file ${filePath}: ${message}`);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Get documents and metadata from the data
195
+ */
196
+ public getDocsAndMetadata(): [string[], Record<string, any>[]] {
197
+ const docs: string[] = [];
198
+ const metadata: Record<string, any>[] = [];
199
+
200
+ if (Array.isArray(this.data)) {
201
+ // Handle array data
202
+ this.data.forEach(item => {
203
+ const content = typeof item === 'string' ? item : item[this.contentCol] || '';
204
+ docs.push(content);
205
+ metadata.push(this.metaCol && typeof item === 'object' ? { [this.metaCol]: item[this.metaCol] } : {});
206
+ });
207
+ } else {
208
+ // Handle record data
209
+ Object.entries(this.data).forEach(([key, value]) => {
210
+ const content = typeof value === 'string' ? value : value[this.contentCol] || '';
211
+ docs.push(content);
212
+ metadata.push(this.metaCol && typeof value === 'object' ? { [this.metaCol]: value[this.metaCol] } : {});
213
+ });
214
+ }
215
+
216
+ return [docs, metadata];
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Repository class implementation
222
+ */
223
+ export class RepoImpl implements Repo {
224
+ public name: string = '';
225
+ public docs: Record<string, Document> = {};
226
+ public codes: Record<string, Document> = {};
227
+ public assets: Record<string, Document> = {};
228
+ public path?: string;
229
+
230
+ constructor(data: Partial<Repo> = {}) {
231
+ Object.assign(this, RepoSchema.parse(data));
232
+ }
233
+
234
+ private _path(filename: string): string {
235
+ if (!this.path) {
236
+ throw new Error('Repository path is not set.');
237
+ }
238
+ return path.join(this.path, filename);
239
+ }
240
+
241
+ /**
242
+ * Create a Repo instance from a directory path
243
+ */
244
+ public static async fromPath(dirPath: string): Promise<RepoImpl> {
245
+ try {
246
+ await fs.mkdir(dirPath, { recursive: true });
247
+ const repo = new RepoImpl({
248
+ path: dirPath,
249
+ name: path.basename(dirPath),
250
+ });
251
+
252
+ // Read all files recursively
253
+ const readDir = async (dir: string) => {
254
+ const entries = await fs.readdir(dir, { withFileTypes: true });
255
+ for (const entry of entries) {
256
+ const fullPath = path.join(dir, entry.name);
257
+ if (entry.isDirectory()) {
258
+ await readDir(fullPath);
259
+ } else {
260
+ const ext = path.extname(entry.name).toLowerCase();
261
+ if (['.json', '.txt', '.md', '.py', '.js', '.css', '.html'].includes(ext)) {
262
+ const content = await fs.readFile(fullPath, 'utf-8');
263
+ await repo._set(content, fullPath);
264
+ }
265
+ }
266
+ }
267
+ };
268
+
269
+ await readDir(dirPath);
270
+ return repo;
271
+ } catch (error: unknown) {
272
+ const message = error instanceof Error ? error.message : String(error);
273
+ throw new Error(`Failed to create repository from ${dirPath}: ${message}`);
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Save all documents to disk
279
+ */
280
+ public async toPath(): Promise<void> {
281
+ const saveAll = async (docs: Record<string, Document>) => {
282
+ for (const doc of Object.values(docs)) {
283
+ if (doc instanceof DocumentImpl && doc.toPath) {
284
+ await doc.toPath();
285
+ }
286
+ }
287
+ };
288
+
289
+ await Promise.all([
290
+ saveAll(this.docs),
291
+ saveAll(this.codes),
292
+ saveAll(this.assets),
293
+ ]);
294
+ }
295
+
296
+ private async _set(content: string, filePath: string): Promise<Document> {
297
+ const ext = path.extname(filePath).toLowerCase();
298
+ const doc = new DocumentImpl({
299
+ content,
300
+ path: filePath,
301
+ name: path.relative(this.path || '', filePath),
302
+ });
303
+
304
+ if (ext === '.md') {
305
+ this.docs[filePath] = doc;
306
+ } else if (['.py', '.js', '.css', '.html'].includes(ext)) {
307
+ this.codes[filePath] = doc;
308
+ } else {
309
+ this.assets[filePath] = doc;
310
+ }
311
+
312
+ return doc;
313
+ }
314
+
315
+ /**
316
+ * Set a document and persist it to disk
317
+ */
318
+ public async set(filename: string, content: string): Promise<void> {
319
+ const filePath = this._path(filename);
320
+ const doc = await this._set(content, filePath);
321
+ await doc.toPath();
322
+ }
323
+
324
+ /**
325
+ * Get a document by its filename
326
+ */
327
+ public get(filename: string): Document | undefined {
328
+ const filePath = this._path(filename);
329
+ return this.docs[filePath] || this.codes[filePath] || this.assets[filePath];
330
+ }
331
+
332
+ /**
333
+ * Get all text documents
334
+ */
335
+ public getTextDocuments(): Document[] {
336
+ return [...Object.values(this.docs), ...Object.values(this.codes)];
337
+ }
338
+
339
+ /**
340
+ * Get repository metadata
341
+ */
342
+ public getMetadata(): RepoMetadata {
343
+ const nDocs = Object.keys(this.docs).length + Object.keys(this.codes).length + Object.keys(this.assets).length;
344
+ const nChars = [...Object.values(this.docs), ...Object.values(this.codes), ...Object.values(this.assets)]
345
+ .reduce((sum, doc) => sum + doc.content.length, 0);
346
+
347
+ return {
348
+ name: this.name,
349
+ nDocs,
350
+ nChars,
351
+ symbols: [], // TODO: Implement symbol extraction
352
+ };
353
+ }
354
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @module LLM
3
+ * @category Core
4
+ */
5
+
6
+ import { z } from 'zod';
7
+
8
+ /**
9
+ * LLM configuration schema
10
+ * Defines settings for language model operations
11
+ */
12
+ export const LLMConfigSchema = z.object({
13
+ /** API key for authentication */
14
+ apiKey: z.string(),
15
+ /** Model name (e.g., 'gpt-4') */
16
+ model: z.string().default('gpt-4'),
17
+ /** Temperature for response generation */
18
+ temperature: z.number().min(0).max(2).default(0.7),
19
+ /** Maximum tokens in response */
20
+ maxTokens: z.number().min(1).default(2000),
21
+ /** Top P sampling */
22
+ topP: z.number().min(0).max(1).default(1),
23
+ /** Frequency penalty */
24
+ frequencyPenalty: z.number().min(-2).max(2).default(0),
25
+ /** Presence penalty */
26
+ presencePenalty: z.number().min(-2).max(2).default(0),
27
+ /** Base URL for API */
28
+ baseURL: z.string().optional(),
29
+ /** Organization ID */
30
+ organization: z.string().optional(),
31
+ /** Proxy URL */
32
+ proxy: z.string().optional(),
33
+ });
34
+
35
+ export type LLMConfig = z.infer<typeof LLMConfigSchema>;
36
+
37
+ /**
38
+ * LLM provider interface
39
+ * Defines methods that must be implemented by LLM providers
40
+ */
41
+ export interface LLMProvider {
42
+ /**
43
+ * Generate text completion
44
+ * @param prompt - Input prompt
45
+ * @param config - Optional configuration overrides
46
+ * @returns Generated text
47
+ */
48
+ generate(prompt: string, config?: Partial<LLMConfig>): Promise<string>;
49
+
50
+ /**
51
+ * Generate text completion as a stream
52
+ * @param prompt - Input prompt
53
+ * @param config - Optional configuration overrides
54
+ * @returns Generated text stream
55
+ */
56
+ generateStream(prompt: string, config?: Partial<LLMConfig>): AsyncIterable<string>;
57
+
58
+ /**
59
+ * Create text embeddings
60
+ * @param text - Input text
61
+ * @returns Embedding vector
62
+ */
63
+ embed(text: string): Promise<number[]>;
64
+ }
@@ -0,0 +1,36 @@
1
+ import { z } from 'zod';
2
+ import type { Message } from './message';
3
+
4
+ export const MemoryConfigSchema = z.object({
5
+ maxSize: z.number().optional(),
6
+ });
7
+
8
+ export type MemoryConfig = z.infer<typeof MemoryConfigSchema>;
9
+
10
+ export class ArrayMemory {
11
+ private messages: Message[] = [];
12
+ private config: MemoryConfig;
13
+
14
+ constructor(config: MemoryConfig = {}) {
15
+ this.config = MemoryConfigSchema.parse(config);
16
+ }
17
+
18
+ add(message: Message): void {
19
+ this.messages.push(message);
20
+ if (this.config.maxSize && this.messages.length > this.config.maxSize) {
21
+ this.messages.shift();
22
+ }
23
+ }
24
+
25
+ get(): Message[] {
26
+ return [...this.messages];
27
+ }
28
+
29
+ getByActions(actions: Set<string>): Message[] {
30
+ return this.messages.filter(msg => actions.has(msg.causedBy));
31
+ }
32
+
33
+ clear(): void {
34
+ this.messages = [];
35
+ }
36
+ }
@@ -0,0 +1,193 @@
1
+ import { z } from 'zod';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+
4
+ /**
5
+ * Message route constants
6
+ */
7
+ export const MESSAGE_ROUTE = {
8
+ CAUSE_BY: 'UserRequirement',
9
+ FROM: '',
10
+ TO: '*',
11
+ TO_ALL: '*',
12
+ } as const;
13
+
14
+ /**
15
+ * Simple message schema without routing information
16
+ */
17
+ export const SimpleMessageSchema = z.object({
18
+ content: z.string(),
19
+ role: z.string(),
20
+ });
21
+
22
+ /**
23
+ * Base message schema with full routing and content information
24
+ */
25
+ export const MessageSchema = z.object({
26
+ id: z.string().default('').transform(id => id || uuidv4()),
27
+ content: z.string(),
28
+ instructContent: z.any().optional().nullable(),
29
+ role: z.string().default('user'),
30
+ causedBy: z.string().default(MESSAGE_ROUTE.CAUSE_BY),
31
+ sentFrom: z.string().default(MESSAGE_ROUTE.FROM),
32
+ sendTo: z.union([
33
+ z.string(),
34
+ z.array(z.string()),
35
+ z.instanceof(Set),
36
+ ]).default(MESSAGE_ROUTE.TO_ALL).transform(data => {
37
+ if (typeof data === 'string') {
38
+ return new Set([data]);
39
+ }
40
+ if (Array.isArray(data)) {
41
+ return new Set(data);
42
+ }
43
+ if (data instanceof Set) {
44
+ return data;
45
+ }
46
+ return new Set([MESSAGE_ROUTE.TO_ALL]);
47
+ }),
48
+ });
49
+
50
+ /**
51
+ * Message types
52
+ */
53
+ export type SimpleMessage = z.infer<typeof SimpleMessageSchema>;
54
+ export type Message = z.infer<typeof MessageSchema>;
55
+
56
+ /**
57
+ * Message queue interface for handling asynchronous message updates
58
+ */
59
+ export interface MessageQueue {
60
+ push(msg: Message): void;
61
+ pop(): Promise<Message | null>;
62
+ popAll(): Promise<Message[]>;
63
+ empty(): boolean;
64
+ }
65
+
66
+ /**
67
+ * Message queue implementation using async queue
68
+ */
69
+ export class AsyncMessageQueue implements MessageQueue {
70
+ private queue: Message[] = [];
71
+
72
+ /**
73
+ * Push a message to the queue
74
+ * @param msg - Message to push
75
+ */
76
+ public push(msg: Message): void {
77
+ this.queue.push(msg);
78
+ }
79
+
80
+ /**
81
+ * Pop a message from the queue
82
+ * @returns Promise resolving to the next message or null if queue is empty
83
+ */
84
+ public async pop(): Promise<Message | null> {
85
+ if (this.queue.length === 0) {
86
+ return null;
87
+ }
88
+ return this.queue.shift() || null;
89
+ }
90
+
91
+ /**
92
+ * Pop all messages from the queue
93
+ * @returns Promise resolving to array of all messages
94
+ */
95
+ public async popAll(): Promise<Message[]> {
96
+ const messages = [...this.queue];
97
+ this.queue = [];
98
+ return messages;
99
+ }
100
+
101
+ /**
102
+ * Check if queue is empty
103
+ * @returns True if queue is empty
104
+ */
105
+ public empty(): boolean {
106
+ return this.queue.length === 0;
107
+ }
108
+
109
+ /**
110
+ * Convert queue to JSON string
111
+ * @returns JSON string representation of queue
112
+ */
113
+ public async dump(): Promise<string> {
114
+ return JSON.stringify({
115
+ messages: this.queue.map(msg => ({
116
+ ...msg,
117
+ sendTo: Array.from(msg.sendTo),
118
+ })),
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Create queue from JSON string
124
+ * @param data - JSON string representation of queue
125
+ * @returns New AsyncMessageQueue instance
126
+ */
127
+ public static load(data: string): AsyncMessageQueue {
128
+ const queue = new AsyncMessageQueue();
129
+ try {
130
+ const parsed = JSON.parse(data);
131
+ if (Array.isArray(parsed.messages)) {
132
+ queue.queue = parsed.messages.map((msg: any) => ({
133
+ ...msg,
134
+ sendTo: new Set(msg.sendTo),
135
+ }));
136
+ }
137
+ } catch (error) {
138
+ console.error('Failed to load message queue:', error);
139
+ }
140
+ return queue;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * User message with predefined role
146
+ */
147
+ export class UserMessage implements Message {
148
+ public id: string = uuidv4();
149
+ public content: string;
150
+ public instructContent: any = null;
151
+ public role: string = 'user';
152
+ public causedBy: string = MESSAGE_ROUTE.CAUSE_BY;
153
+ public sentFrom: string = MESSAGE_ROUTE.FROM;
154
+ public sendTo: Set<string> = new Set([MESSAGE_ROUTE.TO_ALL]);
155
+
156
+ constructor(content: string) {
157
+ this.content = content;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * System message with predefined role
163
+ */
164
+ export class SystemMessage implements Message {
165
+ public id: string = uuidv4();
166
+ public content: string;
167
+ public instructContent: any = null;
168
+ public role: string = 'system';
169
+ public causedBy: string = MESSAGE_ROUTE.CAUSE_BY;
170
+ public sentFrom: string = MESSAGE_ROUTE.FROM;
171
+ public sendTo: Set<string> = new Set([MESSAGE_ROUTE.TO_ALL]);
172
+
173
+ constructor(content: string) {
174
+ this.content = content;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * AI message with predefined role
180
+ */
181
+ export class AIMessage implements Message {
182
+ public id: string = uuidv4();
183
+ public content: string;
184
+ public instructContent: any = null;
185
+ public role: string = 'assistant';
186
+ public causedBy: string = MESSAGE_ROUTE.CAUSE_BY;
187
+ public sentFrom: string = MESSAGE_ROUTE.FROM;
188
+ public sendTo: Set<string> = new Set([MESSAGE_ROUTE.TO_ALL]);
189
+
190
+ constructor(content: string) {
191
+ this.content = content;
192
+ }
193
+ }