graphai 0.0.11 → 0.1.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.
package/README.md CHANGED
@@ -9,6 +9,7 @@ You just need to describe dependencies among those API calls in a single data fl
9
9
  Here is an example:
10
10
 
11
11
  ```YAML
12
+ agentId: sample
12
13
  nodes:
13
14
  taskA:
14
15
  params:
@@ -37,7 +38,7 @@ const sampleAgentFunction = async (context: AgentFunctionContext) => {
37
38
  ...
38
39
  const file = fs.readFileSync(pathToYamlFile, "utf8");
39
40
  const graphData = YAML.parse(file);
40
- const graph = new GraphAI(graphData, sampleAgentFunction);
41
+ const graph = new GraphAI(graphData, { sample: sampleAgentFunction });
41
42
  const results = await graph.run();
42
43
  return results["taskC"];
43
44
  ```
@@ -48,14 +49,14 @@ As Andrew Ng has described in his article, "[The batch: Issue 242](https://www.d
48
49
 
49
50
  Building applications that employ these workflows, however, is challenging due to the complexities of managing multiple asynchronous API calls, including error handling, timeouts, retries, and logging.
50
51
 
51
- GraphAI is designed to simplify this process by decoupling the complexity of multiple asynchronous calls from the application's core logic. It enables developers to model these calls and their dependencies within a single Data Flow Graph, enhancing development and debugging processes.
52
+ GraphAI is designed to simplify this process by decoupling the complexity of multiple asynchronous calls from the application's core logic. It enables developers to model these calls and their dependencies within a single acyclic Data Flow Graph, enhancing development and debugging processes.
52
53
 
53
54
  Furthermore, GraphAI's robust mechanisms for error handling, retry strategies, timeouts, and logging empower developers to concentrate on refining the application logic.
54
55
 
55
56
  ## Quick Install
56
57
 
57
58
  ```
58
- pip install graphai
59
+ npm install graphai
59
60
  ```
60
61
 
61
62
  or
@@ -114,12 +115,43 @@ Key principles:
114
115
 
115
116
  A Data Flow Graph (DFG) is a JavaScript object, which defines the flow of data. It is typically described in YAML file and loaded at runtime.
116
117
 
117
- A DFG consists of a collection of 'nodes', which contains a series of nested keys representing individual nodes in the data flow. Each node is identified by a unique key (e.g., node1, node2) and can contain several predefined keys (params, inputs, outputs, retry, timeout, source, agentId, result, fork) that dictate the node's behavior and its relationship with other nodes.
118
+ A DFG consists of a collection of 'nodes', which contains a series of nested properties representing individual nodes in the data flow. Each node is identified by a unique key, *nodeId* (e.g., node1, node2) and can contain several predefined properties (params, inputs, retry, timeout, agentId, fork, value, update) that dictate the node's behavior and its relationship with other nodes.
119
+
120
+ Connections between nodes will be established by references from one not to another, using either its "inputs" or "update" property. The values of those properties are *data sources*. A *data souce* is specified by either the nodeId (e.g., "node1"), or nodeId + propertyId ("node1.item").
118
121
 
119
122
  ### DFG Structure
120
123
 
121
124
  - 'nodes': A list of node. Required.
122
125
  - 'concurrency': An optional property, which specifies the maximum number of concurrent operations (agent functions to be executed at the same time). The default is 8.
126
+ - 'agentId': An optional property, which specifies the default agent for all the nodes.
127
+ - 'loop': An optional property, which specifies if the graph needs to be executed multiple times. The loop is an JavaScript object, which has two optinoal properties. The *count* property specifies the number of times the graph needs to be executed and the *while* property specifies the condition required to contineu the loop in the form of node name (nodeId) or its property (nodeId.propId). Unlike JavaScript, an empty array will be treated as false.
128
+
129
+ ```
130
+ loop:
131
+ while: people
132
+ nodes:
133
+ people:
134
+ value:
135
+ - Steve Jobs
136
+ - Elon Musk
137
+ - Nikola Tesla
138
+ update: retriever.array
139
+ result:
140
+ value: []
141
+ update: reducer
142
+ retriever:
143
+ agentId: shift
144
+ inputs: [people]
145
+ query:
146
+ agentId: slashgpt
147
+ params:
148
+ manifest:
149
+ prompt: 指定した人について日本語で400字以内で答えて
150
+ inputs: [retriever.item]
151
+ reducer:
152
+ agentId: push
153
+ inputs: [result, query.content]
154
+ ```
123
155
 
124
156
  ## Agent
125
157
 
@@ -133,19 +165,25 @@ An agent function receives two set of parameters via AgentFunctionContext, agent
133
165
 
134
166
  ## Node Structure
135
167
 
136
- - 'inputs': An optional list of node identifiers that the current node depends on. This establishes a flow where the current node can only be executed after the completion of the nodes listed under 'inputs'. If this list is empty and the 'source' property is not set, the associated Agent Function will be immediatley executed.
137
- - 'source': An optional flag, which specifies if the node is a 'source node' or not. A souce node is a special node, which receives data from either an external code (via GraphAI's injectResult method) or from a 'dispatcher node'.
138
- - 'result': An optional object, which injects the result into the source node (equivalent to calling the injectResult method).
168
+ There are two types of Node, *computed nodes* and *static nodes*. A *computed node* is associated with an *agent function*, which receives some inputs, performs some computations asynchronously then returns the result (output). A *static node* is a placeholder of a value (just like a variable in programming language), which is injected by an external program, or is retrived from a *data source* (in case of interations).
169
+
170
+ A *computed node* have following properties.
171
+
172
+ - 'agentId': An **required** property, which specifies the id of the *agent function*.
173
+ - 'inputs': An optional list of *data sources* that the current node depends on. This establishes a flow where the current node can only be executed after the completion of the nodes listed under 'inputs'. If this list is empty, the associated *agent function* will be immediatley executed.
139
174
  - 'retry': An optional number, which specifies the maximum number of retries to be made. If the last attempt fails, that return value will be recorded.
140
175
  - 'timeout': An optional number, which specifies the maximum waittime in msec. If the associated agent function does not return the value in time, the "Timeout" error will be recorded and the returned value will be discarded.
141
- - 'params': An optional parameters to the associated agent function, which are agent specific.
142
- - 'agentId': An optional parameter, which specifies the id of the agent, when the graph is associated with multiple agents.
176
+ - 'params': An optional property to the associated agent function, which are agent specific.
143
177
  - 'fork': An optional paramter, which specifies the number of concurrent transactions to be created for the current node.
144
- - 'outputs': An optinal property, which specifies the mapping from outputId to nodeId. If this property is set, the node become a special node called "dispatcher". A dispatcher node injects result(s) into specified nodes, enabling the dynamic flow of data.
178
+
179
+ A *static* node have following properties.
180
+
181
+ - 'value': An optional property, which specifies the value of this static node (equivalent to calling the injectValue method from outside).
182
+ - 'update': An optional property, which specifies the *data source* after each iteration.
145
183
 
146
184
  ## GraphAI class
147
185
 
148
- ### ```constructor(data: GraphData, callbackDictonary: AgentFunctionDictonary | AgentFunction<any, any, any>)```
186
+ ### ```constructor(data: GraphData, callbackDictonary: AgentFunctionDictonary)```
149
187
  Initializes a new instance of the GraphAI class with the specified graph data and a dictionary of callback functions.
150
188
 
151
189
  - ```data: GraphData```: The graph data including nodes and optional concurrency limit.
@@ -172,7 +210,7 @@ Retrieves all transaction logs recorded during the execution of the graph.
172
210
  Returns: An array of transaction logs detailing the execution states and outcomes of the nodes within the graph.
173
211
 
174
212
  ### ```injectResult(nodeId: string, result: ResultData): void```
175
- Injects a result into a specified node. This is used to manually set the result of a source node, allowing dependent nodes to proceed with execution.
213
+ Injects a result into a specified node. This is used to manually set the result of a static node, allowing dependent nodes to proceed with execution.
176
214
 
177
- - ```nodeId: string```: The ID of the source node into which the result is to be injected.
215
+ - ```nodeId: string```: The ID of the static node into which the result is to be injected.
178
216
  - ```result: ResultData```: The result to be injected into the specified node.
@@ -0,0 +1,4 @@
1
+ import { AgentFunction } from "../graphai";
2
+ export declare const pushAgent: AgentFunction<Record<string, any>, Record<string, any>, Record<string, any>>;
3
+ export declare const popAgent: AgentFunction<Record<string, any>, Record<string, any>, Record<string, any>>;
4
+ export declare const shiftAgent: AgentFunction<Record<string, any>, Record<string, any>, Record<string, any>>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.shiftAgent = exports.popAgent = exports.pushAgent = void 0;
7
+ const deepmerge_1 = __importDefault(require("deepmerge"));
8
+ const pushAgent = async ({ inputs }) => {
9
+ const [array, item] = (0, deepmerge_1.default)({ inputs }, {}).inputs;
10
+ // TODO: Validation
11
+ array.push(item);
12
+ return array;
13
+ };
14
+ exports.pushAgent = pushAgent;
15
+ const popAgent = async (context) => {
16
+ const { inputs } = context;
17
+ const [array] = (0, deepmerge_1.default)({ inputs }, {}).inputs;
18
+ // TODO: Varidation
19
+ const item = array.pop();
20
+ return { array, item };
21
+ };
22
+ exports.popAgent = popAgent;
23
+ const shiftAgent = async (context) => {
24
+ const { inputs } = context;
25
+ const [array] = (0, deepmerge_1.default)({ inputs }, {}).inputs;
26
+ // TODO: Varidation
27
+ const item = array.shift();
28
+ return { array, item };
29
+ };
30
+ exports.shiftAgent = shiftAgent;
@@ -3,3 +3,4 @@ export * from "./slashgpt_agent";
3
3
  export * from "./sleeper_agent";
4
4
  export * from "./data_agent";
5
5
  export * from "./nested_agent";
6
+ export * from "./array_agents";
@@ -19,3 +19,4 @@ __exportStar(require("./slashgpt_agent"), exports);
19
19
  __exportStar(require("./sleeper_agent"), exports);
20
20
  __exportStar(require("./data_agent"), exports);
21
21
  __exportStar(require("./nested_agent"), exports);
22
+ __exportStar(require("./array_agents"), exports);
@@ -2,17 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.nestedAgent = void 0;
4
4
  const graphai_1 = require("../graphai");
5
- const nestedAgent = async ({ params, inputs, agents }) => {
5
+ const nestedAgent = async ({ params, inputs, agents, log }) => {
6
6
  const graph = new graphai_1.GraphAI(params.graph, agents);
7
7
  try {
8
8
  // Inject inputs to specified source nodes
9
9
  (params.inputNodes ?? []).forEach((nodeId, index) => {
10
- graph.injectResult(nodeId, inputs[index]);
10
+ graph.injectValue(nodeId, inputs[index]);
11
11
  });
12
12
  const results = await graph.run();
13
+ log.push(...graph.transactionLogs());
13
14
  return results[params.nodeId];
14
15
  }
15
16
  catch (error) {
17
+ log.push(...graph.transactionLogs());
16
18
  if (error instanceof Error) {
17
19
  console.log("Error:", error.message);
18
20
  }
@@ -14,6 +14,9 @@ const slashGPTAgent = async ({ nodeId, params, inputs, verbose }) => {
14
14
  const session = new slashgpt_1.ChatSession(config, params.manifest ?? {});
15
15
  const query = params?.query ? [params.query] : [];
16
16
  const contents = query.concat(inputs.map((input) => {
17
+ if (typeof input === "string") {
18
+ return input;
19
+ }
17
20
  return input.content;
18
21
  }));
19
22
  session.append_user_question(contents.join("\n"));
@@ -1,10 +1,10 @@
1
1
  import { AgentFunction } from "../graphai";
2
2
  export declare const sleeperAgent: AgentFunction<{
3
3
  duration: number;
4
- result?: Record<string, any>;
4
+ value?: Record<string, any>;
5
5
  }>;
6
6
  export declare const sleeperAgentDebug: AgentFunction<{
7
7
  duration: number;
8
- result?: Record<string, any>;
8
+ value?: Record<string, any>;
9
9
  fail?: boolean;
10
10
  }>;
@@ -11,7 +11,7 @@ const sleeperAgent = async (context) => {
11
11
  await (0, utils_1.sleep)(params.duration);
12
12
  return inputs.reduce((result, input) => {
13
13
  return (0, deepmerge_1.default)(result, input);
14
- }, params.result ?? {});
14
+ }, params.value ?? {});
15
15
  };
16
16
  exports.sleeperAgent = sleeperAgent;
17
17
  const sleeperAgentDebug = async (context) => {
@@ -23,6 +23,6 @@ const sleeperAgentDebug = async (context) => {
23
23
  }
24
24
  return inputs.reduce((result, input) => {
25
25
  return (0, deepmerge_1.default)(result, input);
26
- }, params.result ?? {});
26
+ }, params.value ?? {});
27
27
  };
28
28
  exports.sleeperAgentDebug = sleeperAgentDebug;
package/lib/graphai.d.ts CHANGED
@@ -1,106 +1,36 @@
1
- export declare enum NodeState {
2
- Waiting = "waiting",
3
- Executing = "executing",
4
- Failed = "failed",
5
- TimedOut = "timed-out",
6
- Completed = "completed",
7
- Injected = "injected",
8
- Dispatched = "dispatched"
9
- }
10
- type ResultData<ResultType = Record<string, any>> = ResultType | undefined;
11
- type ResultDataDictonary<ResultType = Record<string, any>> = Record<string, ResultData<ResultType>>;
12
- export type NodeDataParams<ParamsType = Record<string, any>> = ParamsType;
13
- type NodeData = {
14
- inputs?: Array<string>;
15
- params?: NodeDataParams;
16
- retry?: number;
17
- timeout?: number;
18
- agentId?: string;
19
- fork?: number;
20
- source?: boolean;
21
- result?: ResultData;
22
- outputs?: Record<string, string>;
23
- };
24
- export type GraphData = {
25
- nodes: Record<string, NodeData>;
26
- concurrency?: number;
27
- verbose?: boolean;
28
- };
29
- export type TransactionLog = {
30
- nodeId: string;
31
- state: NodeState;
32
- startTime: number;
33
- endTime?: number;
34
- retryCount: number;
35
- agentId?: string;
36
- params?: NodeDataParams;
37
- inputs?: Array<ResultData>;
38
- errorMessage?: string;
39
- result?: ResultData;
40
- };
41
- export type AgentFunctionContext<ParamsType, ResultType, PreviousResultType> = {
42
- nodeId: string;
43
- forkIndex?: number;
44
- retry: number;
45
- params: NodeDataParams<ParamsType>;
46
- inputs: Array<PreviousResultType>;
47
- verbose: boolean;
48
- agents: CallbackDictonaryArgs;
49
- };
50
- export type AgentFunction<ParamsType = Record<string, any>, ResultType = Record<string, any>, PreviousResultType = Record<string, any>> = (context: AgentFunctionContext<ParamsType, ResultType, PreviousResultType>) => Promise<ResultData<ResultType>>;
51
- export type AgentFunctionDictonary = Record<string, AgentFunction<any, any, any>>;
52
- declare class Node {
53
- nodeId: string;
54
- params: NodeDataParams;
55
- inputs: Array<string>;
56
- pendings: Set<string>;
57
- waitlist: Set<string>;
58
- state: NodeState;
59
- agentId?: string;
60
- fork?: number;
61
- forkIndex?: number;
62
- result: ResultData;
63
- retryLimit: number;
64
- retryCount: number;
65
- transactionId: undefined | number;
66
- timeout?: number;
67
- error?: Error;
68
- source: boolean;
69
- outputs?: Record<string, string>;
70
- private graph;
71
- constructor(nodeId: string, forkIndex: number | undefined, data: NodeData, graph: GraphAI);
72
- asString(): string;
73
- private retry;
74
- removePending(nodeId: string): void;
75
- pushQueueIfReady(): void;
76
- injectResult(result: ResultData): void;
77
- private setResult;
78
- execute(): Promise<void>;
79
- }
80
- type GraphNodes = Record<string, Node>;
81
- export type CallbackDictonaryArgs = AgentFunctionDictonary | AgentFunction<any, any, any>;
1
+ export { AgentFunction, AgentFunctionDictonary, GraphData } from "./type";
2
+ import { AgentFunctionDictonary, GraphData, DataSource, TransactionLog, ResultDataDictonary, ResultData, CallbackDictonaryArgs } from "./type";
3
+ import { ComputedNode, StaticNode } from "./node";
4
+ type GraphNodes = Record<string, ComputedNode | StaticNode>;
82
5
  export declare class GraphAI {
6
+ private data;
83
7
  nodes: GraphNodes;
8
+ agentId?: string;
84
9
  callbackDictonary: AgentFunctionDictonary;
85
10
  isRunning: boolean;
86
11
  private runningNodes;
87
12
  private nodeQueue;
88
13
  private onComplete;
89
14
  private concurrency;
15
+ private loop?;
16
+ private repeatCount;
90
17
  verbose: boolean;
91
18
  private logs;
19
+ private createNodes;
20
+ private getValueFromResults;
21
+ private initializeNodes;
92
22
  constructor(data: GraphData, callbackDictonary: CallbackDictonaryArgs);
93
- getCallback(_agentId?: string): AgentFunction<any, any, any>;
23
+ getCallback(agentId?: string): import("./type").AgentFunction<any, any, any>;
94
24
  asString(): string;
95
- results(): ResultDataDictonary<Record<string, any>>;
25
+ results(): ResultDataDictonary;
96
26
  errors(): Record<string, Error>;
27
+ private pushReadyNodesIntoQueue;
97
28
  run(): Promise<ResultDataDictonary>;
98
29
  private runNode;
99
- pushQueue(node: Node): void;
100
- removeRunning(node: Node): void;
30
+ pushQueue(node: ComputedNode): void;
31
+ removeRunning(node: ComputedNode): void;
101
32
  appendLog(log: TransactionLog): void;
102
33
  transactionLogs(): TransactionLog[];
103
- injectResult(nodeId: string, result: ResultData): void;
104
- resultsOf(nodeIds: Array<string>): ResultData<Record<string, any>>[];
34
+ injectValue(nodeId: string, value: ResultData): void;
35
+ resultsOf(sources: Array<DataSource>): any[];
105
36
  }
106
- export {};
package/lib/graphai.js CHANGED
@@ -1,201 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GraphAI = exports.NodeState = void 0;
4
- var NodeState;
5
- (function (NodeState) {
6
- NodeState["Waiting"] = "waiting";
7
- NodeState["Executing"] = "executing";
8
- NodeState["Failed"] = "failed";
9
- NodeState["TimedOut"] = "timed-out";
10
- NodeState["Completed"] = "completed";
11
- NodeState["Injected"] = "injected";
12
- NodeState["Dispatched"] = "dispatched";
13
- })(NodeState || (exports.NodeState = NodeState = {}));
14
- class Node {
15
- constructor(nodeId, forkIndex, data, graph) {
16
- this.waitlist = new Set(); // List of nodes which need data from this node.
17
- this.state = NodeState.Waiting;
18
- this.result = undefined;
19
- this.retryCount = 0;
20
- this.nodeId = nodeId;
21
- this.forkIndex = forkIndex;
22
- this.inputs = data.inputs ?? [];
23
- this.pendings = new Set(this.inputs);
24
- this.params = data.params ?? {};
25
- this.agentId = data.agentId;
26
- this.fork = data.fork;
27
- this.retryLimit = data.retry ?? 0;
28
- this.timeout = data.timeout;
29
- this.source = data.source === true;
30
- this.outputs = data.outputs;
31
- this.graph = graph;
32
- }
33
- asString() {
34
- return `${this.nodeId}: ${this.state} ${[...this.waitlist]}`;
35
- }
36
- retry(state, error) {
37
- if (this.retryCount < this.retryLimit) {
38
- this.retryCount++;
39
- this.execute();
40
- }
41
- else {
42
- this.state = state;
43
- this.result = undefined;
44
- this.error = error;
45
- this.transactionId = undefined; // This is necessary for timeout case
46
- this.graph.removeRunning(this);
47
- }
48
- }
49
- removePending(nodeId) {
50
- this.pendings.delete(nodeId);
51
- if (this.graph.isRunning) {
52
- this.pushQueueIfReady();
53
- }
54
- }
55
- pushQueueIfReady() {
56
- if (this.pendings.size === 0 && !this.source) {
57
- this.graph.pushQueue(this);
58
- }
59
- }
60
- injectResult(result) {
61
- if (this.source) {
62
- const log = {
63
- nodeId: this.nodeId,
64
- retryCount: this.retryCount,
65
- state: NodeState.Injected,
66
- startTime: Date.now(),
67
- endTime: Date.now(),
68
- result,
69
- };
70
- this.graph.appendLog(log);
71
- this.setResult(result, NodeState.Injected);
72
- }
73
- else {
74
- console.error("- injectResult called on non-source node.", this.nodeId);
75
- }
76
- }
77
- setResult(result, state) {
78
- this.state = state;
79
- this.result = result;
80
- this.waitlist.forEach((nodeId) => {
81
- const node = this.graph.nodes[nodeId];
82
- // Todo: Avoid running before Run()
83
- node.removePending(this.nodeId);
84
- });
85
- }
86
- async execute() {
87
- const results = this.graph.resultsOf(this.inputs);
88
- const transactionId = Date.now();
89
- const log = {
90
- nodeId: this.nodeId,
91
- retryCount: this.retryCount,
92
- state: NodeState.Executing,
93
- startTime: transactionId,
94
- agentId: this.agentId,
95
- params: this.params,
96
- inputs: results,
97
- };
98
- this.graph.appendLog(log);
99
- this.state = NodeState.Executing;
100
- this.transactionId = transactionId;
101
- if (this.timeout && this.timeout > 0) {
102
- setTimeout(() => {
103
- if (this.state === NodeState.Executing && this.transactionId === transactionId) {
104
- console.log(`-- ${this.nodeId}: timeout ${this.timeout}`);
105
- log.errorMessage = "Timeout";
106
- log.state = NodeState.TimedOut;
107
- log.endTime = Date.now();
108
- this.retry(NodeState.TimedOut, Error("Timeout"));
109
- }
110
- }, this.timeout);
111
- }
112
- try {
113
- const callback = this.graph.getCallback(this.agentId);
114
- const result = await callback({
115
- nodeId: this.nodeId,
116
- retry: this.retryCount,
117
- params: this.params,
118
- inputs: results,
119
- forkIndex: this.forkIndex,
120
- verbose: this.graph.verbose,
121
- agents: this.graph.callbackDictonary,
122
- });
123
- if (this.transactionId !== transactionId) {
124
- console.log(`-- ${this.nodeId}: transactionId mismatch`);
125
- return;
126
- }
127
- log.endTime = Date.now();
128
- log.result = result;
129
- const outputs = this.outputs;
130
- if (outputs !== undefined) {
131
- Object.keys(result).forEach((outputId) => {
132
- const nodeId = outputs[outputId];
133
- this.graph.injectResult(nodeId, result[outputId]);
134
- });
135
- log.state = NodeState.Dispatched;
136
- this.state = NodeState.Dispatched;
137
- this.graph.removeRunning(this);
138
- return;
139
- }
140
- log.state = NodeState.Completed;
141
- this.setResult(result, NodeState.Completed);
142
- this.graph.removeRunning(this);
143
- }
144
- catch (error) {
145
- if (this.transactionId !== transactionId) {
146
- console.log(`-- ${this.nodeId}: transactionId mismatch(error)`);
147
- return;
148
- }
149
- log.state = NodeState.Failed;
150
- log.endTime = Date.now();
151
- if (error instanceof Error) {
152
- log.errorMessage = error.message;
153
- this.retry(NodeState.Failed, error);
154
- }
155
- else {
156
- console.error(`-- ${this.nodeId}: Unexpecrted error was caught`);
157
- log.errorMessage = "Unknown";
158
- this.retry(NodeState.Failed, Error("Unknown"));
159
- }
160
- }
161
- }
162
- }
3
+ exports.GraphAI = void 0;
4
+ const node_1 = require("./node");
5
+ const utils_1 = require("./utils/utils");
163
6
  const defaultConcurrency = 8;
164
7
  class GraphAI {
165
- constructor(data, callbackDictonary) {
166
- this.isRunning = false;
167
- this.runningNodes = new Set();
168
- this.nodeQueue = [];
169
- this.logs = [];
170
- this.callbackDictonary = typeof callbackDictonary === "function" ? { _default: callbackDictonary } : callbackDictonary;
171
- this.concurrency = data.concurrency ?? defaultConcurrency;
172
- this.verbose = data.verbose === true;
173
- this.onComplete = () => {
174
- console.error("-- SOMETHING IS WRONG: onComplete is called without run()");
175
- };
8
+ createNodes(data) {
176
9
  const nodeId2forkedNodeIds = {};
177
10
  const forkedNodeId2Index = {};
178
- // Create node instances from data.nodes
179
- this.nodes = Object.keys(data.nodes).reduce((nodes, nodeId) => {
11
+ const forkedNodeId2NodeId = {}; // for sources
12
+ const nodes = Object.keys(data.nodes).reduce((_nodes, nodeId) => {
180
13
  const fork = data.nodes[nodeId].fork;
14
+ const isStaticNode = (data.nodes[nodeId].agentId ?? data.agentId) === undefined;
15
+ const node = isStaticNode ? node_1.StaticNode : node_1.ComputedNode;
181
16
  if (fork) {
182
17
  // For fork, change the nodeId and increase the node
183
18
  nodeId2forkedNodeIds[nodeId] = new Array(fork).fill(undefined).map((_, i) => {
184
19
  const forkedNodeId = `${nodeId}_${i}`;
185
- nodes[forkedNodeId] = new Node(forkedNodeId, i, data.nodes[nodeId], this);
20
+ _nodes[forkedNodeId] = new node(forkedNodeId, i, data.nodes[nodeId], this);
186
21
  // Data for pending and waiting
187
22
  forkedNodeId2Index[forkedNodeId] = i;
23
+ forkedNodeId2NodeId[forkedNodeId] = nodeId;
188
24
  return forkedNodeId;
189
25
  });
190
26
  }
191
27
  else {
192
- nodes[nodeId] = new Node(nodeId, undefined, data.nodes[nodeId], this);
28
+ _nodes[nodeId] = new node(nodeId, undefined, data.nodes[nodeId], this);
193
29
  }
194
- return nodes;
30
+ return _nodes;
195
31
  }, {});
196
32
  // Generate the waitlist for each node, and update the pendings in case of forked node.
197
- Object.keys(this.nodes).forEach((nodeId) => {
198
- const node = this.nodes[nodeId];
33
+ Object.keys(nodes).forEach((nodeId) => {
34
+ const node = nodes[nodeId];
199
35
  node.pendings.forEach((pending) => {
200
36
  // If the pending(previous) node is forking
201
37
  if (nodeId2forkedNodeIds[pending]) {
@@ -203,36 +39,83 @@ class GraphAI {
203
39
  if (node.fork) {
204
40
  // 1:1 if current nodes are also forking.
205
41
  const newPendingId = nodeId2forkedNodeIds[pending][forkedNodeId2Index[nodeId]];
206
- this.nodes[newPendingId].waitlist.add(nodeId); // previousNode
42
+ nodes[newPendingId].waitlist.add(nodeId); // previousNode
207
43
  node.pendings.add(newPendingId);
208
44
  }
209
45
  else {
210
46
  // 1:n if current node is not forking.
211
47
  nodeId2forkedNodeIds[pending].forEach((newPendingId) => {
212
- this.nodes[newPendingId].waitlist.add(nodeId); // previousNode
48
+ nodes[newPendingId].waitlist.add(nodeId); // previousNode
213
49
  node.pendings.add(newPendingId);
214
50
  });
215
51
  }
216
52
  node.pendings.delete(pending);
217
53
  }
218
54
  else {
219
- this.nodes[pending].waitlist.add(nodeId); // previousNode
55
+ if (nodes[pending]) {
56
+ nodes[pending].waitlist.add(nodeId); // previousNode
57
+ }
58
+ else {
59
+ console.error(`--- invalid input ${pending} for node, ${nodeId}`);
60
+ }
220
61
  }
221
62
  });
222
63
  node.inputs = Array.from(node.pendings); // for fork.
64
+ node.sources = node.inputs.reduce((sources, input) => {
65
+ const refNodeId = forkedNodeId2NodeId[input] ?? input;
66
+ sources[input] = { nodeId: input, propId: node.sources[refNodeId].propId };
67
+ return sources;
68
+ }, {});
223
69
  });
70
+ return nodes;
71
+ }
72
+ getValueFromResults(key, results) {
73
+ const source = (0, utils_1.parseNodeName)(key);
74
+ const result = results[source.nodeId];
75
+ return result ? (source.propId ? result[source.propId] : result) : undefined;
76
+ }
77
+ // for static
78
+ initializeNodes(previousResults) {
224
79
  // If the result property is specified, inject it.
225
- // NOTE: This must be done at the end of this constructor
226
- Object.keys(data.nodes).forEach((nodeId) => {
227
- const result = data.nodes[nodeId].result;
228
- if (result) {
229
- this.injectResult(nodeId, result);
80
+ // If the previousResults exists (indicating we are in a loop),
81
+ // process the update property (nodeId or nodeId.propId).
82
+ Object.keys(this.data.nodes).forEach((nodeId) => {
83
+ const node = this.nodes[nodeId];
84
+ if (node?.isStaticNode) {
85
+ const value = node?.value;
86
+ const update = node?.update;
87
+ if (value) {
88
+ this.injectValue(nodeId, value);
89
+ }
90
+ if (update && previousResults) {
91
+ const result = this.getValueFromResults(update, previousResults);
92
+ if (result) {
93
+ this.injectValue(nodeId, result);
94
+ }
95
+ }
230
96
  }
231
97
  });
232
98
  }
233
- getCallback(_agentId) {
234
- const agentId = _agentId ?? "_default";
235
- if (this.callbackDictonary[agentId]) {
99
+ constructor(data, callbackDictonary) {
100
+ this.isRunning = false;
101
+ this.runningNodes = new Set();
102
+ this.nodeQueue = []; // for Computed Node
103
+ this.repeatCount = 0;
104
+ this.logs = [];
105
+ this.data = data;
106
+ this.callbackDictonary = callbackDictonary;
107
+ this.concurrency = data.concurrency ?? defaultConcurrency;
108
+ this.loop = data.loop;
109
+ this.agentId = data.agentId;
110
+ this.verbose = data.verbose === true;
111
+ this.onComplete = () => {
112
+ console.error("-- SOMETHING IS WRONG: onComplete is called without run()");
113
+ };
114
+ this.nodes = this.createNodes(data);
115
+ this.initializeNodes();
116
+ }
117
+ getCallback(agentId) {
118
+ if (agentId && this.callbackDictonary[agentId]) {
236
119
  return this.callbackDictonary[agentId];
237
120
  }
238
121
  throw new Error("No agent: " + agentId);
@@ -256,22 +139,29 @@ class GraphAI {
256
139
  errors() {
257
140
  return Object.keys(this.nodes).reduce((errors, nodeId) => {
258
141
  const node = this.nodes[nodeId];
259
- if (node.error !== undefined) {
260
- errors[nodeId] = node.error;
142
+ if (node.isComputedNode) {
143
+ if (node.error !== undefined) {
144
+ errors[nodeId] = node.error;
145
+ }
261
146
  }
262
147
  return errors;
263
148
  }, {});
264
149
  }
150
+ pushReadyNodesIntoQueue() {
151
+ // Nodes without pending data should run immediately.
152
+ Object.keys(this.nodes).forEach((nodeId) => {
153
+ const node = this.nodes[nodeId];
154
+ if (node.isComputedNode) {
155
+ node.pushQueueIfReady();
156
+ }
157
+ });
158
+ }
265
159
  async run() {
266
160
  if (this.isRunning) {
267
161
  console.error("-- Already Running");
268
162
  }
269
163
  this.isRunning = true;
270
- // Nodes without pending data should run immediately.
271
- Object.keys(this.nodes).forEach((nodeId) => {
272
- const node = this.nodes[nodeId];
273
- node.pushQueueIfReady();
274
- });
164
+ this.pushReadyNodesIntoQueue();
275
165
  return new Promise((resolve, reject) => {
276
166
  this.onComplete = () => {
277
167
  this.isRunning = false;
@@ -286,10 +176,12 @@ class GraphAI {
286
176
  };
287
177
  });
288
178
  }
179
+ // for computed
289
180
  runNode(node) {
290
181
  this.runningNodes.add(node.nodeId);
291
182
  node.execute();
292
183
  }
184
+ // for computed
293
185
  pushQueue(node) {
294
186
  if (this.runningNodes.size < this.concurrency) {
295
187
  this.runNode(node);
@@ -298,6 +190,7 @@ class GraphAI {
298
190
  this.nodeQueue.push(node);
299
191
  }
300
192
  }
193
+ // for completed
301
194
  removeRunning(node) {
302
195
  this.runningNodes.delete(node.nodeId);
303
196
  if (this.nodeQueue.length > 0) {
@@ -307,6 +200,27 @@ class GraphAI {
307
200
  }
308
201
  }
309
202
  if (this.runningNodes.size === 0) {
203
+ this.repeatCount++;
204
+ const loop = this.loop;
205
+ if (loop && (loop.count === undefined || this.repeatCount < loop.count)) {
206
+ const results = this.results(); // results from previous loop
207
+ this.isRunning = false; // temporarily stop it
208
+ this.nodes = this.createNodes(this.data);
209
+ this.initializeNodes(results);
210
+ const checkWhileCondition = () => {
211
+ if (loop.while) {
212
+ const value = this.getValueFromResults(loop.while, this.results());
213
+ // NOTE: We treat an empty array as false.
214
+ return Array.isArray(value) ? value.length > 0 : !!value;
215
+ }
216
+ return true;
217
+ };
218
+ if (checkWhileCondition()) {
219
+ this.isRunning = true; // restore it
220
+ this.pushReadyNodesIntoQueue();
221
+ return;
222
+ }
223
+ }
310
224
  this.onComplete();
311
225
  }
312
226
  }
@@ -316,18 +230,19 @@ class GraphAI {
316
230
  transactionLogs() {
317
231
  return this.logs;
318
232
  }
319
- injectResult(nodeId, result) {
233
+ injectValue(nodeId, value) {
320
234
  const node = this.nodes[nodeId];
321
- if (node) {
322
- node.injectResult(result);
235
+ if (node && node.isStaticNode) {
236
+ node.injectValue(value);
323
237
  }
324
238
  else {
325
239
  console.error("-- Invalid nodeId", nodeId);
326
240
  }
327
241
  }
328
- resultsOf(nodeIds) {
329
- return nodeIds.map((nodeId) => {
330
- return this.nodes[nodeId].result;
242
+ resultsOf(sources) {
243
+ return sources.map((source) => {
244
+ const result = this.nodes[source.nodeId].result;
245
+ return result && source.propId ? result[source.propId] : result;
331
246
  });
332
247
  }
333
248
  }
@@ -9,7 +9,7 @@ const experimental_agents_1 = require("./experimental_agents");
9
9
  const fs_1 = __importDefault(require("fs"));
10
10
  const path_1 = __importDefault(require("path"));
11
11
  const yaml_1 = __importDefault(require("yaml"));
12
- const testAgent = async (context) => {
12
+ const testAgent = async () => {
13
13
  return {};
14
14
  };
15
15
  const main = async () => {
package/lib/log.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { ResultData, TransactionLog, NodeDataParams } from "./type";
2
+ export declare const injectValueLog: (nodeId: string, value: ResultData) => TransactionLog;
3
+ export declare const executeLog: (nodeId: string, retryCount: number, transactionId: number, agentId: string | undefined, params: NodeDataParams, results: ResultData[]) => TransactionLog;
4
+ export declare const timeoutLog: (log: TransactionLog) => void;
5
+ export declare const callbackLog: (log: TransactionLog, result: ResultData, localLog: TransactionLog[]) => void;
6
+ export declare const errorLog: (log: TransactionLog, errorMessage: string) => void;
package/lib/log.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.errorLog = exports.callbackLog = exports.timeoutLog = exports.executeLog = exports.injectValueLog = void 0;
4
+ const type_1 = require("./type");
5
+ const injectValueLog = (nodeId, value) => {
6
+ const log = {
7
+ nodeId,
8
+ state: type_1.NodeState.Injected,
9
+ startTime: Date.now(),
10
+ endTime: Date.now(),
11
+ result: value,
12
+ };
13
+ return log;
14
+ };
15
+ exports.injectValueLog = injectValueLog;
16
+ const executeLog = (nodeId, retryCount, transactionId, agentId, params, results) => {
17
+ const log = {
18
+ nodeId,
19
+ retryCount: retryCount > 0 ? retryCount : undefined,
20
+ state: type_1.NodeState.Executing,
21
+ startTime: transactionId,
22
+ agentId,
23
+ params,
24
+ inputs: results.length > 0 ? results : undefined,
25
+ };
26
+ return log;
27
+ };
28
+ exports.executeLog = executeLog;
29
+ const timeoutLog = (log) => {
30
+ log.errorMessage = "Timeout";
31
+ log.state = type_1.NodeState.TimedOut;
32
+ log.endTime = Date.now();
33
+ };
34
+ exports.timeoutLog = timeoutLog;
35
+ const callbackLog = (log, result, localLog) => {
36
+ log.endTime = Date.now();
37
+ log.result = result;
38
+ if (localLog.length > 0) {
39
+ log.log = localLog;
40
+ }
41
+ };
42
+ exports.callbackLog = callbackLog;
43
+ const errorLog = (log, errorMessage) => {
44
+ log.state = type_1.NodeState.Failed;
45
+ log.endTime = Date.now();
46
+ log.errorMessage = errorMessage;
47
+ };
48
+ exports.errorLog = errorLog;
package/lib/node.d.ts ADDED
@@ -0,0 +1,44 @@
1
+ import type { NodeDataParams, ResultData, DataSource, NodeData } from "./type";
2
+ import type { GraphAI } from "./graphai";
3
+ import { NodeState } from "./type";
4
+ export declare class Node {
5
+ nodeId: string;
6
+ sources: Record<string, DataSource>;
7
+ anyInput: boolean;
8
+ inputs: Array<string>;
9
+ pendings: Set<string>;
10
+ waitlist: Set<string>;
11
+ state: NodeState;
12
+ fork?: number;
13
+ forkIndex?: number;
14
+ result: ResultData;
15
+ transactionId: undefined | number;
16
+ protected graph: GraphAI;
17
+ constructor(nodeId: string, forkIndex: number | undefined, data: NodeData, graph: GraphAI);
18
+ asString(): string;
19
+ removePending(nodeId: string): void;
20
+ protected setResult(result: ResultData, state: NodeState): void;
21
+ }
22
+ export declare class ComputedNode extends Node {
23
+ params: NodeDataParams;
24
+ retryLimit: number;
25
+ retryCount: number;
26
+ agentId?: string;
27
+ timeout?: number;
28
+ error?: Error;
29
+ readonly isStaticNode = false;
30
+ readonly isComputedNode = true;
31
+ constructor(nodeId: string, forkIndex: number | undefined, data: NodeData, graph: GraphAI);
32
+ pushQueueIfReady(): void;
33
+ private retry;
34
+ removePending(nodeId: string): void;
35
+ execute(): Promise<void>;
36
+ }
37
+ export declare class StaticNode extends Node {
38
+ value?: ResultData;
39
+ update?: string;
40
+ readonly isStaticNode = true;
41
+ readonly isComputedNode = false;
42
+ constructor(nodeId: string, forkIndex: number | undefined, data: NodeData, graph: GraphAI);
43
+ injectValue(value: ResultData): void;
44
+ }
package/lib/node.js ADDED
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StaticNode = exports.ComputedNode = exports.Node = void 0;
4
+ const type_1 = require("./type");
5
+ const utils_1 = require("./utils/utils");
6
+ const log_1 = require("./log");
7
+ class Node {
8
+ constructor(nodeId, forkIndex, data, graph) {
9
+ this.sources = {}; // data sources.
10
+ this.waitlist = new Set(); // List of nodes which need data from this node.
11
+ this.state = type_1.NodeState.Waiting;
12
+ this.result = undefined;
13
+ this.nodeId = nodeId;
14
+ this.forkIndex = forkIndex;
15
+ this.anyInput = data.anyInput ?? false;
16
+ this.inputs = (data.inputs ?? []).map((input) => {
17
+ const source = (0, utils_1.parseNodeName)(input);
18
+ this.sources[source.nodeId] = source;
19
+ return source.nodeId;
20
+ });
21
+ this.pendings = new Set(this.inputs);
22
+ this.fork = data.fork;
23
+ this.graph = graph;
24
+ }
25
+ asString() {
26
+ return `${this.nodeId}: ${this.state} ${[...this.waitlist]}`;
27
+ }
28
+ removePending(nodeId) {
29
+ if (this.anyInput) {
30
+ const [result] = this.graph.resultsOf([this.sources[nodeId]]);
31
+ if (result) {
32
+ this.pendings.clear();
33
+ }
34
+ }
35
+ else {
36
+ this.pendings.delete(nodeId);
37
+ }
38
+ }
39
+ setResult(result, state) {
40
+ this.state = state;
41
+ this.result = result;
42
+ this.waitlist.forEach((nodeId) => {
43
+ const node = this.graph.nodes[nodeId];
44
+ // Todo: Avoid running before Run()
45
+ node.removePending(this.nodeId);
46
+ });
47
+ }
48
+ }
49
+ exports.Node = Node;
50
+ class ComputedNode extends Node {
51
+ constructor(nodeId, forkIndex, data, graph) {
52
+ super(nodeId, forkIndex, data, graph);
53
+ this.retryCount = 0;
54
+ this.isStaticNode = false;
55
+ this.isComputedNode = true;
56
+ this.params = data.params ?? {};
57
+ this.agentId = data.agentId ?? graph.agentId;
58
+ this.retryLimit = data.retry ?? 0;
59
+ this.timeout = data.timeout;
60
+ }
61
+ // for completed
62
+ pushQueueIfReady() {
63
+ if (this.pendings.size === 0) {
64
+ // If input property is specified, we need to ensure that the property value exists.
65
+ const count = this.inputs.reduce((count, nodeId) => {
66
+ const source = this.sources[nodeId];
67
+ if (source.propId) {
68
+ const [result] = this.graph.resultsOf([source]);
69
+ if (!result) {
70
+ return count;
71
+ }
72
+ }
73
+ return count + 1;
74
+ }, 0);
75
+ if ((this.anyInput && count > 0) || count == this.inputs.length) {
76
+ this.graph.pushQueue(this);
77
+ }
78
+ }
79
+ }
80
+ // for computed
81
+ retry(state, error) {
82
+ if (this.retryCount < this.retryLimit) {
83
+ this.retryCount++;
84
+ this.execute();
85
+ }
86
+ else {
87
+ this.state = state;
88
+ this.result = undefined;
89
+ this.error = error;
90
+ this.transactionId = undefined; // This is necessary for timeout case
91
+ this.graph.removeRunning(this);
92
+ }
93
+ }
94
+ removePending(nodeId) {
95
+ super.removePending(nodeId);
96
+ if (this.graph.isRunning) {
97
+ this.pushQueueIfReady();
98
+ }
99
+ }
100
+ async execute() {
101
+ const results = this.graph
102
+ .resultsOf(this.inputs.map((input) => {
103
+ return this.sources[input];
104
+ }))
105
+ .filter((result) => {
106
+ // Remove undefined if anyInput flag is set.
107
+ return !this.anyInput || result !== undefined;
108
+ });
109
+ const transactionId = Date.now();
110
+ const log = (0, log_1.executeLog)(this.nodeId, this.retryCount, transactionId, this.agentId, this.params, results);
111
+ this.graph.appendLog(log);
112
+ this.state = type_1.NodeState.Executing;
113
+ this.transactionId = transactionId;
114
+ if (this.timeout && this.timeout > 0) {
115
+ setTimeout(() => {
116
+ if (this.state === type_1.NodeState.Executing && this.transactionId === transactionId) {
117
+ console.log(`-- ${this.nodeId}: timeout ${this.timeout}`);
118
+ (0, log_1.timeoutLog)(log);
119
+ this.retry(type_1.NodeState.TimedOut, Error("Timeout"));
120
+ }
121
+ }, this.timeout);
122
+ }
123
+ try {
124
+ const callback = this.graph.getCallback(this.agentId);
125
+ const localLog = [];
126
+ const result = await callback({
127
+ nodeId: this.nodeId,
128
+ retry: this.retryCount,
129
+ params: this.params,
130
+ inputs: results,
131
+ forkIndex: this.forkIndex,
132
+ verbose: this.graph.verbose,
133
+ agents: this.graph.callbackDictonary,
134
+ log: localLog,
135
+ });
136
+ if (this.transactionId !== transactionId) {
137
+ console.log(`-- ${this.nodeId}: transactionId mismatch`);
138
+ return;
139
+ }
140
+ (0, log_1.callbackLog)(log, result, localLog);
141
+ log.state = type_1.NodeState.Completed;
142
+ this.setResult(result, type_1.NodeState.Completed);
143
+ this.graph.removeRunning(this);
144
+ }
145
+ catch (error) {
146
+ if (this.transactionId !== transactionId) {
147
+ console.log(`-- ${this.nodeId}: transactionId mismatch(error)`);
148
+ return;
149
+ }
150
+ const isError = error instanceof Error;
151
+ (0, log_1.errorLog)(log, isError ? error.message : "Unknown");
152
+ if (isError) {
153
+ this.retry(type_1.NodeState.Failed, error);
154
+ }
155
+ else {
156
+ console.error(`-- ${this.nodeId}: Unexpecrted error was caught`);
157
+ this.retry(type_1.NodeState.Failed, Error("Unknown"));
158
+ }
159
+ }
160
+ }
161
+ }
162
+ exports.ComputedNode = ComputedNode;
163
+ class StaticNode extends Node {
164
+ constructor(nodeId, forkIndex, data, graph) {
165
+ super(nodeId, forkIndex, data, graph);
166
+ this.isStaticNode = true;
167
+ this.isComputedNode = false;
168
+ this.value = data.value;
169
+ this.update = data.update;
170
+ }
171
+ // for static
172
+ injectValue(value) {
173
+ const log = (0, log_1.injectValueLog)(this.nodeId, value);
174
+ this.graph.appendLog(log);
175
+ this.setResult(value, type_1.NodeState.Injected);
176
+ //console.error("- injectValue called on non-source node.", this.nodeId);
177
+ }
178
+ }
179
+ exports.StaticNode = StaticNode;
package/lib/type.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ export declare enum NodeState {
2
+ Waiting = "waiting",
3
+ Executing = "executing",
4
+ Failed = "failed",
5
+ TimedOut = "timed-out",
6
+ Completed = "completed",
7
+ Injected = "injected",
8
+ Dispatched = "dispatched"
9
+ }
10
+ export type ResultData<ResultType = Record<string, any>> = ResultType | undefined;
11
+ export type ResultDataDictonary<ResultType = Record<string, any>> = Record<string, ResultData<ResultType>>;
12
+ export type NodeDataParams<ParamsType = Record<string, any>> = ParamsType;
13
+ export type DataSource = {
14
+ nodeId: string;
15
+ propId?: string;
16
+ };
17
+ export type NodeData = {
18
+ inputs?: Array<string>;
19
+ anyInput?: boolean;
20
+ params?: NodeDataParams;
21
+ retry?: number;
22
+ timeout?: number;
23
+ agentId?: string;
24
+ fork?: number;
25
+ value?: ResultData;
26
+ update?: string;
27
+ };
28
+ export type LoopData = {
29
+ count?: number;
30
+ while?: string;
31
+ };
32
+ export type GraphData = {
33
+ agentId?: string;
34
+ nodes: Record<string, NodeData>;
35
+ concurrency?: number;
36
+ loop?: LoopData;
37
+ verbose?: boolean;
38
+ };
39
+ export type TransactionLog = {
40
+ nodeId: string;
41
+ state: NodeState;
42
+ startTime: number;
43
+ endTime?: number;
44
+ retryCount?: number;
45
+ agentId?: string;
46
+ params?: NodeDataParams;
47
+ inputs?: Array<ResultData>;
48
+ errorMessage?: string;
49
+ result?: ResultData;
50
+ log?: TransactionLog[];
51
+ };
52
+ export type AgentFunctionContext<ParamsType, PreviousResultType> = {
53
+ nodeId: string;
54
+ forkIndex?: number;
55
+ retry: number;
56
+ params: NodeDataParams<ParamsType>;
57
+ inputs: Array<PreviousResultType>;
58
+ verbose: boolean;
59
+ agents: CallbackDictonaryArgs;
60
+ log: TransactionLog[];
61
+ };
62
+ export type AgentFunction<ParamsType = Record<string, any>, ResultType = Record<string, any>, PreviousResultType = Record<string, any>> = (context: AgentFunctionContext<ParamsType, PreviousResultType>) => Promise<ResultData<ResultType>>;
63
+ export type AgentFunctionDictonary = Record<string, AgentFunction<any, any, any>>;
64
+ export type CallbackDictonaryArgs = AgentFunctionDictonary;
package/lib/type.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NodeState = void 0;
4
+ var NodeState;
5
+ (function (NodeState) {
6
+ NodeState["Waiting"] = "waiting";
7
+ NodeState["Executing"] = "executing";
8
+ NodeState["Failed"] = "failed";
9
+ NodeState["TimedOut"] = "timed-out";
10
+ NodeState["Completed"] = "completed";
11
+ NodeState["Injected"] = "injected";
12
+ NodeState["Dispatched"] = "dispatched";
13
+ })(NodeState || (exports.NodeState = NodeState = {}));
@@ -1 +1,3 @@
1
+ import { DataSource } from "../type";
1
2
  export declare const sleep: (milliseconds: number) => Promise<unknown>;
3
+ export declare const parseNodeName: (name: string) => DataSource;
@@ -1,7 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sleep = void 0;
3
+ exports.parseNodeName = exports.sleep = void 0;
4
4
  const sleep = async (milliseconds) => {
5
5
  return await new Promise((resolve) => setTimeout(resolve, milliseconds));
6
6
  };
7
7
  exports.sleep = sleep;
8
+ const parseNodeName = (name) => {
9
+ const parts = name.split(".");
10
+ if (parts.length == 1) {
11
+ return { nodeId: parts[0] };
12
+ }
13
+ else {
14
+ return { nodeId: parts[0], propId: parts[1] };
15
+ }
16
+ };
17
+ exports.parseNodeName = parseNodeName;
package/lib/utils.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export declare const parseNodeName: (name: string) => {
2
+ sourceNodeId: string;
3
+ propId?: undefined;
4
+ } | {
5
+ sourceNodeId: string;
6
+ propId: string;
7
+ };
package/lib/utils.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseNodeName = void 0;
4
+ const parseNodeName = (name) => {
5
+ const parts = name.split(".");
6
+ if (parts.length == 1) {
7
+ return { sourceNodeId: parts[0] };
8
+ }
9
+ else {
10
+ return { sourceNodeId: parts[0], propId: parts[1] };
11
+ }
12
+ };
13
+ exports.parseNodeName = parseNodeName;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphai",
3
- "version": "0.0.11",
3
+ "version": "0.1.0",
4
4
  "description": "Asynchronous data flow execution engine to make it simple to build LLM apps.",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -11,7 +11,7 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "build": "tsc && tsc-alias",
14
- "eslint": "eslint --fix --ext src/**/*.{ts} tests/**/*.ts",
14
+ "eslint": "eslint --fix --ext .ts ./src ./tests ./samples",
15
15
  "format": "prettier --write '{src,tests,samples}/**/*.ts' .eslintrc.js",
16
16
  "test": "node --test -r tsconfig-paths/register --require ts-node/register ./tests/**/test_*.ts",
17
17
  "cli": "npx ts-node -r tsconfig-paths/register ./src/graphai_cli.ts",