@ai.ntellect/core 0.5.0 → 0.6.0

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 (131) hide show
  1. package/.mocharc.json +1 -1
  2. package/README.md +311 -272
  3. package/dist/graph/controller.js +63 -0
  4. package/dist/graph/engine.js +563 -0
  5. package/dist/index.js +6 -6
  6. package/dist/memory/adapters/meilisearch/index.js +249 -0
  7. package/dist/memory/adapters/redis/index.js +96 -0
  8. package/dist/memory/index.js +9 -0
  9. package/dist/services/agenda.js +115 -0
  10. package/dist/services/embedding.js +40 -0
  11. package/dist/services/queue.js +99 -103
  12. package/dist/test/graph/controller.test.js +170 -0
  13. package/dist/test/graph/engine.test.js +465 -0
  14. package/dist/test/memory/adapters/meilisearch.test.js +250 -0
  15. package/dist/test/memory/adapters/redis.test.js +143 -0
  16. package/dist/test/memory/base.test.js +209 -0
  17. package/dist/test/services/agenda.test.js +230 -0
  18. package/dist/test/services/queue.test.js +258 -0
  19. package/dist/types/index.js +2 -0
  20. package/dist/utils/generate-object.js +32 -11
  21. package/dist/utils/inject-actions.js +2 -2
  22. package/dist/utils/queue-item-transformer.js +2 -2
  23. package/dist/utils/state-manager.js +20 -0
  24. package/graph/controller.ts +60 -0
  25. package/{services/workflow.ts → graph/engine.ts} +331 -113
  26. package/index.ts +7 -7
  27. package/interfaces/index.ts +119 -0
  28. package/memory/adapters/meilisearch/index.ts +286 -0
  29. package/memory/adapters/redis/index.ts +103 -0
  30. package/memory/index.ts +22 -0
  31. package/package.json +7 -2
  32. package/services/agenda.ts +48 -43
  33. package/services/embedding.ts +26 -0
  34. package/services/queue.ts +2 -29
  35. package/test/.env.test +4 -0
  36. package/test/graph/controller.test.ts +186 -0
  37. package/test/graph/engine.test.ts +563 -0
  38. package/test/memory/adapters/meilisearch.test.ts +297 -0
  39. package/test/memory/adapters/redis.test.ts +160 -0
  40. package/test/memory/base.test.ts +229 -0
  41. package/test/services/agenda.test.ts +280 -0
  42. package/test/services/queue.test.ts +286 -44
  43. package/tsconfig.json +10 -10
  44. package/types/index.ts +270 -0
  45. package/utils/generate-object.js +111 -0
  46. package/utils/header-builder.js +34 -0
  47. package/utils/inject-actions.js +16 -0
  48. package/utils/queue-item-transformer.js +24 -0
  49. package/utils/queue-item-transformer.ts +8 -11
  50. package/utils/sanitize-results.js +60 -0
  51. package/utils/schema-generator.js +46 -0
  52. package/utils/state-manager.js +20 -0
  53. package/utils/state-manager.ts +17 -12
  54. package/.nvmrc +0 -1
  55. package/README.FR.md +0 -916
  56. package/agent/index.ts +0 -151
  57. package/agent/workflow/conditions.ts +0 -16
  58. package/agent/workflow/handlers/interpreter.handler.ts +0 -48
  59. package/agent/workflow/handlers/memory.handler.ts +0 -106
  60. package/agent/workflow/handlers/orchestrator.handler.ts +0 -23
  61. package/agent/workflow/handlers/queue.handler.ts +0 -34
  62. package/agent/workflow/handlers/scheduler.handler.ts +0 -61
  63. package/agent/workflow/index.ts +0 -62
  64. package/dist/agent/index.d.ts +0 -38
  65. package/dist/agent/index.js +0 -143
  66. package/dist/agent/tools/get-rss.d.ts +0 -16
  67. package/dist/agent/tools/get-rss.js +0 -62
  68. package/dist/bull.d.ts +0 -1
  69. package/dist/bull.js +0 -9
  70. package/dist/examples/index.d.ts +0 -2
  71. package/dist/examples/index.js +0 -89
  72. package/dist/index.d.ts +0 -7
  73. package/dist/llm/interpreter/context.d.ts +0 -15
  74. package/dist/llm/interpreter/context.js +0 -89
  75. package/dist/llm/interpreter/index.d.ts +0 -21
  76. package/dist/llm/interpreter/index.js +0 -87
  77. package/dist/llm/memory-manager/context.d.ts +0 -2
  78. package/dist/llm/memory-manager/context.js +0 -22
  79. package/dist/llm/memory-manager/index.d.ts +0 -17
  80. package/dist/llm/memory-manager/index.js +0 -107
  81. package/dist/llm/orchestrator/context.d.ts +0 -2
  82. package/dist/llm/orchestrator/context.js +0 -23
  83. package/dist/llm/orchestrator/index.d.ts +0 -44
  84. package/dist/llm/orchestrator/index.js +0 -139
  85. package/dist/llm/orchestrator/types.d.ts +0 -12
  86. package/dist/memory/cache.d.ts +0 -22
  87. package/dist/memory/cache.js +0 -165
  88. package/dist/memory/persistent.d.ts +0 -57
  89. package/dist/memory/persistent.js +0 -189
  90. package/dist/services/queue.d.ts +0 -13
  91. package/dist/services/redis-cache.d.ts +0 -37
  92. package/dist/services/redis-cache.js +0 -93
  93. package/dist/services/scheduler.d.ts +0 -40
  94. package/dist/services/scheduler.js +0 -99
  95. package/dist/services/telegram-monitor.d.ts +0 -0
  96. package/dist/services/telegram-monitor.js +0 -118
  97. package/dist/t.d.ts +0 -46
  98. package/dist/t.js +0 -102
  99. package/dist/test.d.ts +0 -0
  100. package/dist/test.js +0 -438
  101. package/dist/types.d.ts +0 -258
  102. package/dist/types.js +0 -22
  103. package/dist/utils/generate-object.d.ts +0 -12
  104. package/dist/utils/header-builder.d.ts +0 -11
  105. package/dist/utils/inject-actions.d.ts +0 -2
  106. package/dist/utils/queue-item-transformer.d.ts +0 -7
  107. package/dist/utils/sanitize-results.d.ts +0 -17
  108. package/dist/utils/schema-generator.d.ts +0 -16
  109. package/examples/actions/get-rss.ts +0 -71
  110. package/examples/index.ts +0 -98
  111. package/index.html +0 -42
  112. package/llm/dynamic-condition/example.ts +0 -36
  113. package/llm/dynamic-condition/index.ts +0 -108
  114. package/llm/interpreter/context.ts +0 -94
  115. package/llm/interpreter/index.ts +0 -140
  116. package/llm/memory-manager/context.ts +0 -19
  117. package/llm/memory-manager/index.ts +0 -115
  118. package/llm/orchestrator/context.ts +0 -19
  119. package/llm/orchestrator/index.ts +0 -192
  120. package/llm/orchestrator/types.ts +0 -14
  121. package/memory/cache.ts +0 -221
  122. package/memory/persistent.ts +0 -265
  123. package/script.js +0 -167
  124. package/services/cache.ts +0 -298
  125. package/services/telegram-monitor.ts +0 -138
  126. package/t.py +0 -79
  127. package/t.ts +0 -25
  128. package/test/llm/orchestrator.test.ts +0 -47
  129. package/test/llm/synthesizer.test.ts +0 -31
  130. package/types.ts +0 -367
  131. /package/dist/{llm/orchestrator/types.js → interfaces/index.js} +0 -0
@@ -1,23 +1,24 @@
1
+ import { Persistence, RealTimeNotifier } from "@/interfaces";
2
+ import { GraphDefinition, Node, NodeRelationship, SharedState } from "@/types";
1
3
  import { configDotenv } from "dotenv";
2
4
  import EventEmitter from "events";
3
- import {
4
- mergeState,
5
- Node,
6
- Persistence,
7
- RealTimeNotifier,
8
- SharedState,
9
- WorkflowDefinition,
10
- } from "../types";
5
+ import { z } from "zod";
11
6
 
12
7
  configDotenv();
13
8
 
9
+ interface GraphOptions<T> {
10
+ initialState?: SharedState<T>;
11
+ schema?: z.ZodSchema<T>;
12
+ autoDetectCycles?: boolean;
13
+ }
14
+
14
15
  /**
15
16
  * Represents a directed worflow structure capable of executing nodes in sequence or parallel.
16
17
  * The worflow can handle state management, event emissions, and conditional execution paths.
17
18
  *
18
19
  * @template T - The type of data stored in the worflow's context
19
20
  */
20
- export class Workflow<T> {
21
+ export class GraphEngine<T> {
21
22
  /** Stores global context data accessible to all nodes */
22
23
  public globalContext: Map<string, any>;
23
24
 
@@ -39,18 +40,19 @@ export class Workflow<T> {
39
40
  /** Optional notifier for real-time updates */
40
41
  private notifier: RealTimeNotifier | null;
41
42
 
43
+ private schema?: z.ZodSchema<T>;
44
+
45
+ private currentState: SharedState<T>;
46
+
42
47
  /**
43
- * Creates a new Workflow instance.
48
+ * Creates a new Graph instance.
44
49
  *
45
- * @param {WorkflowDefinition<T>} [definition] - Initial worflow structure and configuration
50
+ * @param {GraphDefinition<T>} [definition] - Initial worflow structure and configuration
46
51
  * @param {Object} [config] - Additional configuration options
47
52
  * @param {boolean} [config.autoDetectCycles] - Whether to check for cycles during initialization
48
53
  * @throws {Error} If cycles are detected when autoDetectCycles is true
49
54
  */
50
- constructor(
51
- definition?: WorkflowDefinition<T>,
52
- config?: { autoDetectCycles?: boolean }
53
- ) {
55
+ constructor(definition?: GraphDefinition<T>, options?: GraphOptions<T>) {
54
56
  this.name = definition?.name || "anonymous";
55
57
  this.eventEmitter = new EventEmitter();
56
58
  this.globalContext = new Map();
@@ -58,13 +60,19 @@ export class Workflow<T> {
58
60
  this.executedNodes = new Set();
59
61
  this.persistence = null;
60
62
  this.notifier = null;
63
+ this.schema = options?.schema;
64
+ this.currentState = { context: {} } as SharedState<T>;
61
65
 
62
66
  if (definition) {
63
67
  this.loadFromDefinition(definition);
64
68
  }
65
69
 
66
- if (config?.autoDetectCycles && this.checkForCycles()) {
67
- throw new Error("Cycle detected in the worflow");
70
+ if (options?.autoDetectCycles && this.checkForCycles()) {
71
+ throw new Error("Cycle detected in the workflow");
72
+ }
73
+
74
+ if (options?.initialState) {
75
+ this.setState(options.initialState);
68
76
  }
69
77
  }
70
78
 
@@ -113,13 +121,13 @@ export class Workflow<T> {
113
121
  /**
114
122
  * Loads a worflow structure from a definition object.
115
123
  * @private
116
- * @param {WorkflowDefinition<T>} definition - The worflow definition
124
+ * @param {GraphDefinition<T>} definition - The worflow definition
117
125
  */
118
- private loadFromDefinition(definition: WorkflowDefinition<T>): void {
126
+ private loadFromDefinition(definition: GraphDefinition<T>): void {
119
127
  Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
120
128
  this.addNode(nodeConfig, {
121
129
  condition: nodeConfig.condition,
122
- next: nodeConfig.next,
130
+ relationships: nodeConfig.relationships,
123
131
  });
124
132
  });
125
133
  }
@@ -142,14 +150,15 @@ export class Workflow<T> {
142
150
  recStack.add(nodeName);
143
151
 
144
152
  const currentNode = this.nodes.get(nodeName);
145
- if (currentNode?.next) {
146
- for (const nextNode of currentNode.next) {
153
+ if (currentNode?.relationships) {
154
+ for (const relation of currentNode.relationships) {
155
+ const targetNode = relation.name;
147
156
  if (
148
- !visited.has(nextNode) &&
149
- this.isCyclic(nextNode, visited, recStack)
157
+ !visited.has(targetNode) &&
158
+ this.isCyclic(targetNode, visited, recStack)
150
159
  ) {
151
160
  return true;
152
- } else if (recStack.has(nextNode)) {
161
+ } else if (recStack.has(targetNode)) {
153
162
  return true;
154
163
  }
155
164
  }
@@ -180,28 +189,27 @@ export class Workflow<T> {
180
189
  * @param {Node<T>} node - The node to add
181
190
  * @param {Object} options - Node configuration options
182
191
  * @param {Function} [options.condition] - Condition function for node execution
183
- * @param {string[]} [options.next] - Array of next node names
192
+ * @param {string[]} [options.relations] - Array of relations node names
184
193
  * @param {string[]} [options.events] - Array of event names to listen for
185
194
  */
186
195
  addNode(
187
196
  node: Node<T>,
188
197
  {
189
198
  condition,
190
- next,
199
+ relationships,
191
200
  events,
192
201
  }: {
193
202
  condition?: (state: SharedState<T>) => boolean;
194
- next?: string[];
203
+ relationships?: NodeRelationship[];
195
204
  events?: string[];
196
205
  }
197
206
  ): void {
198
- node.next = next;
207
+ node.relationships = relationships;
199
208
  node.condition = condition;
200
209
 
201
210
  if (events) {
202
211
  events.forEach((event) => {
203
212
  this.eventEmitter.on(event, async (data) => {
204
- console.log(`Event "${event}" received by node "${node.name}"`);
205
213
  const state = data.state || {};
206
214
  await this.execute(state, node.name);
207
215
  });
@@ -217,30 +225,24 @@ export class Workflow<T> {
217
225
  * @param {any} data - Data to pass with the event
218
226
  */
219
227
  public emit(eventName: string, data: any): void {
220
- console.log(`Event "${eventName}" emitted with data:`, data);
221
228
  this.eventEmitter.emit(eventName, data);
222
229
  }
223
230
 
224
231
  /**
225
232
  * Adds a subworflow as a node in the current worflow.
226
- * @param {Workflow<T>} subWorkflow - The subworflow to add
233
+ * @param {Graph<T>} subGraph - The subworflow to add
227
234
  * @param {string} entryNode - The entry node name in the subworflow
228
235
  * @param {string} name - The name for the subworflow node
229
236
  */
230
- addSubWorkflow(
231
- subWorkflow: Workflow<T>,
232
- entryNode: string,
233
- name: string
234
- ): void {
235
- const subWorkflowNode: Node<T> = {
236
- name,
237
+ addSubGraph(subGraph: GraphEngine<T>, entryNode: string, name: string): void {
238
+ const subGraphNode: Node<T> = {
239
+ name: name,
237
240
  execute: async (state) => {
238
- console.log(`Executing subworflow: ${name}`);
239
- await subWorkflow.execute(state, entryNode);
241
+ await subGraph.execute(state, entryNode);
240
242
  return state;
241
243
  },
242
244
  };
243
- this.nodes.set(name, subWorkflowNode);
245
+ this.nodes.set(name, subGraphNode);
244
246
  }
245
247
 
246
248
  /**
@@ -255,75 +257,105 @@ export class Workflow<T> {
255
257
  startNode: string,
256
258
  onStream?: (state: SharedState<T>) => void,
257
259
  onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
258
- ): Promise<void> {
259
- let currentNodeName = startNode;
260
-
261
- while (currentNodeName) {
262
- this.executedNodes.add(currentNodeName);
260
+ ): Promise<SharedState<T>> {
261
+ try {
262
+ if (this.schema) {
263
+ try {
264
+ this.schema.parse(state.context);
265
+ } catch (error) {
266
+ const validationError = new Error(
267
+ `Initial state validation failed: ${
268
+ error instanceof Error ? error.message : error
269
+ }`
270
+ );
271
+ if (onError) onError(validationError, startNode, state);
272
+ throw validationError;
273
+ }
274
+ }
263
275
 
264
- const currentNode = this.nodes.get(currentNodeName);
265
- if (!currentNode) throw new Error(`Node ${currentNodeName} not found.`);
276
+ this.setState(state);
277
+ let currentNodeName = startNode;
266
278
 
267
- if (currentNode.condition && !currentNode.condition(state)) {
268
- console.log(
269
- `Condition for node "${currentNodeName}" not met. Ending Workflow.`
270
- );
271
- break;
272
- }
279
+ while (currentNodeName) {
280
+ this.executedNodes.add(currentNodeName);
281
+ const currentNode = this.nodes.get(currentNodeName);
282
+ if (!currentNode) throw new Error(`Node ${currentNodeName} not found.`);
273
283
 
274
- try {
275
- if (this.notifier) {
276
- this.notifier.notify("nodeExecutionStarted", {
277
- worflow: this.name,
278
- node: currentNodeName,
279
- });
284
+ if (
285
+ currentNode.condition &&
286
+ !currentNode.condition(this.currentState)
287
+ ) {
288
+ break;
280
289
  }
281
290
 
282
- console.log(`Executing node: ${currentNodeName}`);
283
- const newState = await currentNode.execute(state);
284
- Object.assign(state, mergeState(state, newState));
291
+ try {
292
+ if (this.notifier) {
293
+ this.notifier.notify("nodeExecutionStarted", {
294
+ workflow: this.name,
295
+ node: currentNodeName,
296
+ });
297
+ }
285
298
 
286
- if (onStream) onStream(state);
299
+ const params = currentNode.schema?.parse(this.currentState);
300
+ const newState = await currentNode.execute(
301
+ params || {},
302
+ this.currentState
303
+ );
287
304
 
288
- if (this.persistence) {
289
- await this.persistence.saveState(this.name, state, currentNodeName);
290
- }
305
+ if (newState) {
306
+ this.setState(newState);
307
+ if (onStream) onStream(this.currentState);
308
+ }
291
309
 
292
- if (this.notifier) {
293
- await this.notifier.notify("nodeExecutionCompleted", {
294
- worflow: this.name,
295
- node: currentNodeName,
296
- state,
297
- });
310
+ if (this.persistence) {
311
+ await this.persistence.saveState(
312
+ this.name,
313
+ this.currentState,
314
+ currentNodeName
315
+ );
316
+ }
317
+
318
+ if (this.notifier) {
319
+ await this.notifier.notify("nodeExecutionCompleted", {
320
+ workflow: this.name,
321
+ node: currentNodeName,
322
+ state: this.currentState,
323
+ });
324
+ }
325
+ } catch (error) {
326
+ if (onError)
327
+ onError(error as Error, currentNodeName, this.currentState);
328
+ if (this.notifier) {
329
+ this.notifier.notify("nodeExecutionFailed", {
330
+ workflow: this.name,
331
+ node: currentNodeName,
332
+ state: this.currentState,
333
+ error,
334
+ });
335
+ }
336
+ break;
298
337
  }
299
- } catch (error) {
300
- console.error(`Error in node ${currentNodeName}:`, error);
301
- if (onError) onError(error as Error, currentNodeName, state);
302
- if (this.notifier) {
303
- this.notifier.notify("nodeExecutionFailed", {
304
- worflow: this.name,
305
- node: currentNodeName,
306
- state,
307
- error,
308
- });
338
+
339
+ const relationsNodes = currentNode.relationships || [];
340
+ if (relationsNodes.length > 1) {
341
+ await Promise.all(
342
+ relationsNodes.map((relation) =>
343
+ this.execute(this.currentState, relation.name, onStream, onError)
344
+ )
345
+ );
346
+ break;
347
+ } else {
348
+ currentNodeName = relationsNodes[0]?.name || "";
309
349
  }
310
- break;
311
350
  }
312
351
 
313
- const nextNodes = currentNode.next || [];
314
- if (nextNodes.length > 1) {
315
- await Promise.all(
316
- nextNodes.map((nextNode) =>
317
- this.execute(state, nextNode, onStream, onError)
318
- )
319
- );
320
- break;
321
- } else {
322
- currentNodeName = nextNodes[0] || "";
352
+ return this.getState();
353
+ } catch (error) {
354
+ if (onError) {
355
+ onError(error as Error, startNode, state);
323
356
  }
357
+ throw error;
324
358
  }
325
-
326
- console.log(`Workflow completed for node: ${startNode}`);
327
359
  }
328
360
 
329
361
  /**
@@ -341,8 +373,6 @@ export class Workflow<T> {
341
373
  onStream?: (state: SharedState<T>) => void,
342
374
  onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
343
375
  ): Promise<void> {
344
- console.log(`Executing nodes in parallel: ${nodeNames.join(", ")}`);
345
-
346
376
  const executeWithLimit = async (nodeName: string) => {
347
377
  await this.execute(state, nodeName, onStream, onError);
348
378
  };
@@ -359,18 +389,19 @@ export class Workflow<T> {
359
389
 
360
390
  /**
361
391
  * Updates the worflow structure with a new definition.
362
- * @param {WorkflowDefinition<T>} definition - The new worflow definition
392
+ * @param {GraphDefinition<T>} definition - The new worflow definition
363
393
  */
364
- updateWorkflow(definition: WorkflowDefinition<T>): void {
394
+ updateGraph(definition: GraphDefinition<T>): void {
365
395
  Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
366
396
  if (this.nodes.has(nodeConfig.name)) {
367
397
  const existingNode = this.nodes.get(nodeConfig.name)!;
368
- existingNode.next = nodeConfig.next || existingNode.next;
398
+ existingNode.relationships =
399
+ nodeConfig.relationships || existingNode.relationships;
369
400
  existingNode.condition = nodeConfig.condition || existingNode.condition;
370
401
  } else {
371
402
  this.addNode(nodeConfig, {
372
403
  condition: nodeConfig.condition,
373
- next: nodeConfig.next,
404
+ relationships: nodeConfig.relationships,
374
405
  });
375
406
  }
376
407
  });
@@ -378,9 +409,9 @@ export class Workflow<T> {
378
409
 
379
410
  /**
380
411
  * Replace the worflow with a new definition.
381
- * @param {WorkflowDefinition<T>} definition - The new worflow definition
412
+ * @param {GraphDefinition<T>} definition - The new worflow definition
382
413
  */
383
- replaceWorkflow(definition: WorkflowDefinition<T>): void {
414
+ replaceGraph(definition: GraphDefinition<T>): void {
384
415
  this.nodes.clear();
385
416
  this.loadFromDefinition(definition);
386
417
  }
@@ -396,10 +427,10 @@ export class Workflow<T> {
396
427
  * @returns {string} Mermaid diagram syntax representing the worflow
397
428
  */
398
429
  generateMermaidDiagram(title?: string): string {
399
- const lines: string[] = ["worflow TD"];
430
+ const lines: string[] = ["flowchart TD"];
400
431
 
401
432
  if (title) {
402
- lines.push(` subworflow ${title}`);
433
+ lines.push(` subgraph ${title}`);
403
434
  }
404
435
 
405
436
  // Add nodes with styling
@@ -424,21 +455,21 @@ export class Workflow<T> {
424
455
 
425
456
  // Add connections
426
457
  this.nodes.forEach((node, nodeName) => {
427
- if (node.next) {
428
- node.next.forEach((nextNode) => {
458
+ if (node.relationships) {
459
+ node.relationships.forEach((relationsNode) => {
429
460
  let connectionStyle = "";
430
461
  if (node.condition) {
431
462
  connectionStyle = "---|condition|"; // Add label for conditional connections
432
463
  } else {
433
464
  connectionStyle = "-->"; // Normal connection
434
465
  }
435
- lines.push(` ${nodeName} ${connectionStyle} ${nextNode}`);
466
+ lines.push(` ${nodeName} ${connectionStyle} ${relationsNode}`);
436
467
  });
437
468
  }
438
469
 
439
470
  // Add event connections if any
440
471
  if (node.events && node.events.length > 0) {
441
- node.events.forEach((event) => {
472
+ node.events.forEach((event: string) => {
442
473
  const eventNodeId = `${event}_event`;
443
474
  lines.push(` ${eventNodeId}((${event})):::event`);
444
475
  lines.push(` ${eventNodeId} -.->|trigger| ${nodeName}`);
@@ -471,7 +502,7 @@ export class Workflow<T> {
471
502
  console.log("```\n");
472
503
  }
473
504
 
474
- exportWorkflowToJson<T>(worflow: WorkflowDefinition<T>): string {
505
+ exportGraphToJson<T>(worflow: GraphDefinition<T>): string {
475
506
  const result = {
476
507
  worflowName: worflow.name,
477
508
  entryNode: worflow.entryNode,
@@ -481,11 +512,198 @@ export class Workflow<T> {
481
512
  description: node.description || "No description provided",
482
513
  execute: node.execute.name,
483
514
  condition: node.condition ? node.condition.toString() : "None",
484
- next: node.next || [],
515
+ relationships: node.relationships || [],
485
516
  };
486
517
  return acc;
487
518
  }, {} as Record<string, any>),
488
519
  };
489
520
  return JSON.stringify(result, null, 2);
490
521
  }
522
+
523
+ /**
524
+ * Generates a visual representation of the workflow schema.
525
+ * Displays the structure of the data expected for each node.
526
+ *
527
+ * @returns {string} A formatted string describing the workflow schema
528
+ */
529
+ visualizeSchema(): string {
530
+ const output: string[] = [];
531
+
532
+ output.push(`📋 Graph: ${this.name}`);
533
+ output.push("=".repeat(50));
534
+
535
+ if (this.schema) {
536
+ output.push("🔷 Global Schema:");
537
+ output.push("-".repeat(30));
538
+
539
+ if (this.schema instanceof z.ZodObject) {
540
+ const shape = this.schema.shape;
541
+ Object.entries(shape).forEach(([key, value]) => {
542
+ const description = this.describeZodType(value as z.ZodType, 1);
543
+ output.push(`${key}:`);
544
+ output.push(description);
545
+ });
546
+ }
547
+ output.push("");
548
+ }
549
+
550
+ output.push("🔷 Nodes:");
551
+ output.push("-".repeat(30));
552
+
553
+ this.nodes.forEach((node, nodeName) => {
554
+ output.push(`\n📍 Node: ${nodeName}`);
555
+ output.push(
556
+ `Description: ${node.description || "No description provided"}`
557
+ );
558
+
559
+ if (node.relationships && node.relationships.length > 0) {
560
+ output.push(`Next nodes: ${node.relationships.join(", ")}`);
561
+ }
562
+
563
+ output.push("");
564
+ });
565
+
566
+ return output.join("\n");
567
+ }
568
+
569
+ /**
570
+ * Recursively describes a Zod type.
571
+ */
572
+ public describeZodType(type: z.ZodType, indent: number = 0): string {
573
+ const padding = " ".repeat(indent);
574
+
575
+ if (type instanceof z.ZodObject) {
576
+ const shape = type.shape;
577
+ const lines: string[] = [];
578
+
579
+ Object.entries(shape).forEach(([key, value]) => {
580
+ const isOptional = value instanceof z.ZodOptional;
581
+ const actualType = isOptional
582
+ ? (value as z.ZodOptional<z.ZodType<any, any, any>>).unwrap()
583
+ : (value as z.ZodType<any, any, any>);
584
+ const description = this.describeZodType(actualType, indent + 1);
585
+
586
+ lines.push(`${padding}${key}${isOptional ? "?" : ""}: ${description}`);
587
+ });
588
+
589
+ return lines.join("\n");
590
+ }
591
+
592
+ if (type instanceof z.ZodArray) {
593
+ const elementType = this.describeZodType(type.element, indent);
594
+ return `Array<${elementType}>`;
595
+ }
596
+
597
+ if (type instanceof z.ZodString) {
598
+ const checks = type._def.checks || [];
599
+ const constraints = checks
600
+ .map((check) => {
601
+ if (check.kind === "url") return "url";
602
+ if (check.kind === "email") return "email";
603
+ return check.kind;
604
+ })
605
+ .join(", ");
606
+
607
+ return constraints ? `string (${constraints})` : "string";
608
+ }
609
+
610
+ if (type instanceof z.ZodNumber) {
611
+ return "number";
612
+ }
613
+
614
+ if (type instanceof z.ZodBoolean) {
615
+ return "boolean";
616
+ }
617
+
618
+ if (type instanceof z.ZodOptional) {
619
+ return `${this.describeZodType(type.unwrap(), indent)} (optional)`;
620
+ }
621
+
622
+ return type.constructor.name.replace("Zod", "") || "unknown";
623
+ }
624
+
625
+ /**
626
+ * Updates the state of a node.
627
+ * @param {SharedState<T>} state - The current state
628
+ * @param {Partial<T>} updates - The updates to apply
629
+ * @returns {SharedState<T>} The updated state
630
+ */
631
+ protected updateNodeState(state: SharedState<T>, updates: Partial<T>) {
632
+ return {
633
+ ...state,
634
+ context: {
635
+ ...(state.context || {}),
636
+ ...updates,
637
+ },
638
+ };
639
+ }
640
+
641
+ /**
642
+ * Retrieves the current state of the workflow.
643
+ * @returns {SharedState<T>} The current state
644
+ */
645
+ public getState(): SharedState<T> {
646
+ return this.currentState;
647
+ }
648
+
649
+ /**
650
+ * Sets the state of the workflow.
651
+ * @param {Partial<SharedState<T>>} state - The new state
652
+ */
653
+ public setState(state: Partial<SharedState<T>>): void {
654
+ this.currentState = this.mergeStates(this.currentState, state);
655
+
656
+ if (state.context) {
657
+ Object.entries(state.context).forEach(([key, value]) => {
658
+ this.globalContext.set(key, value);
659
+ });
660
+ }
661
+ const currentNode = Array.from(this.executedNodes).pop();
662
+ if (currentNode) {
663
+ const node = this.nodes.get(currentNode);
664
+ if (node) {
665
+ node.state = {
666
+ ...(node.state || {}),
667
+ ...(state.context || {}),
668
+ };
669
+ }
670
+ }
671
+ }
672
+
673
+ /**
674
+ * Merges two states.
675
+ * @param {SharedState<T>} currentState - The current state
676
+ * @param {Partial<SharedState<T>>} newState - The new state
677
+ * @returns {SharedState<T>} The merged state
678
+ */
679
+ private mergeStates(
680
+ currentState: SharedState<T>,
681
+ newState: Partial<SharedState<T>>
682
+ ): SharedState<T> {
683
+ return {
684
+ ...currentState,
685
+ context: {
686
+ ...(currentState.context || {}),
687
+ ...(newState.context || {}),
688
+ },
689
+ };
690
+ }
691
+
692
+ /**
693
+ * Updates the state of the workflow.
694
+ * @param {Partial<SharedState<T>>} updates - The updates to apply
695
+ * @returns {SharedState<T>} The updated state
696
+ */
697
+ public updateState(updates: Partial<SharedState<T>>): SharedState<T> {
698
+ const currentState = this.getState();
699
+ const newState = {
700
+ ...currentState,
701
+ context: {
702
+ ...currentState.context,
703
+ ...(updates.context || {}),
704
+ },
705
+ };
706
+ this.setState(newState);
707
+ return newState;
708
+ }
491
709
  }
package/index.ts CHANGED
@@ -1,8 +1,8 @@
1
- export * from "./agent";
2
- export * from "./llm/interpreter";
3
- export * from "./llm/interpreter/context";
4
- export * from "./llm/orchestrator";
5
- export * from "./types";
1
+ export * from "./graph/controller";
2
+ export * from "./graph/engine";
3
+ export * from "./memory";
4
+ export * from "./memory/adapters/meilisearch";
5
+ export * from "./memory/adapters/redis";
6
6
 
7
- export * from "./memory/cache";
8
- export * from "./memory/persistent";
7
+ export * from "./interfaces";
8
+ export * from "./types";