graphai 0.0.12 → 0.1.1
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 +14 -10
- package/lib/experimental_agents/array_agents/index.d.ts +3 -0
- package/lib/experimental_agents/array_agents/index.js +9 -0
- package/lib/experimental_agents/array_agents/pop_agent.d.ts +2 -0
- package/lib/experimental_agents/array_agents/pop_agent.js +15 -0
- package/lib/experimental_agents/array_agents/push_agent.d.ts +2 -0
- package/lib/experimental_agents/array_agents/push_agent.js +14 -0
- package/lib/experimental_agents/array_agents/shift_agent.d.ts +2 -0
- package/lib/experimental_agents/{array_agents.js → array_agents/shift_agent.js} +2 -17
- package/lib/experimental_agents/data_agents/data_object_merge_template_agent.d.ts +2 -0
- package/lib/experimental_agents/data_agents/data_object_merge_template_agent.js +13 -0
- package/lib/experimental_agents/data_agents/data_sum_template_agent.d.ts +17 -0
- package/lib/experimental_agents/data_agents/data_sum_template_agent.js +30 -0
- package/lib/experimental_agents/data_agents/index.d.ts +3 -0
- package/lib/experimental_agents/data_agents/index.js +9 -0
- package/lib/experimental_agents/data_agents/total_agent.d.ts +46 -0
- package/lib/experimental_agents/data_agents/total_agent.js +51 -0
- package/lib/experimental_agents/embedding_agent.d.ts +6 -0
- package/lib/experimental_agents/embedding_agent.js +43 -0
- package/lib/experimental_agents/index.d.ts +8 -3
- package/lib/experimental_agents/index.js +8 -3
- package/lib/experimental_agents/map_agent.d.ts +4 -0
- package/lib/experimental_agents/map_agent.js +46 -0
- package/lib/experimental_agents/matrix_agent.d.ts +9 -0
- package/lib/experimental_agents/matrix_agent.js +50 -0
- package/lib/experimental_agents/nested_agent.d.ts +2 -2
- package/lib/experimental_agents/nested_agent.js +14 -8
- package/lib/experimental_agents/slashgpt_agent.d.ts +1 -1
- package/lib/experimental_agents/slashgpt_agent.js +2 -7
- package/lib/experimental_agents/sleeper_agents/index.d.ts +2 -0
- package/lib/experimental_agents/sleeper_agents/index.js +7 -0
- package/lib/experimental_agents/sleeper_agents/sleeper_agent.d.ts +5 -0
- package/lib/experimental_agents/sleeper_agents/sleeper_agent.js +16 -0
- package/lib/experimental_agents/sleeper_agents/sleeper_agent_debug.d.ts +6 -0
- package/lib/experimental_agents/{sleeper_agent.js → sleeper_agents/sleeper_agent_debug.js} +4 -13
- package/lib/experimental_agents/string_agents/index.d.ts +2 -0
- package/lib/experimental_agents/string_agents/index.js +7 -0
- package/lib/experimental_agents/string_agents/string_splitter_agent.d.ts +7 -0
- package/lib/experimental_agents/string_agents/string_splitter_agent.js +24 -0
- package/lib/experimental_agents/string_agents/string_template_agent.d.ts +4 -0
- package/lib/experimental_agents/{string_agent.js → string_agents/string_template_agent.js} +2 -5
- package/lib/experimental_agents/test_agents/bypass_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/bypass_agent.js +10 -0
- package/lib/experimental_agents/test_agents/copy_message_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/copy_message_agent.js +11 -0
- package/lib/experimental_agents/test_agents/counting_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/counting_agent.js +11 -0
- package/lib/experimental_agents/test_agents/echo_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/echo_agent.js +7 -0
- package/lib/experimental_agents/test_agents/echo_fork_index_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/echo_fork_index_agent.js +7 -0
- package/lib/experimental_agents/test_agents/index.d.ts +5 -0
- package/lib/experimental_agents/test_agents/index.js +13 -0
- package/lib/experimental_agents/test_agents/merge_node_id_agent.d.ts +2 -0
- package/lib/experimental_agents/test_agents/merge_node_id_agent.js +10 -0
- package/lib/experimental_agents/token_agent.d.ts +6 -0
- package/lib/experimental_agents/token_agent.js +33 -0
- package/lib/graphai.d.ts +28 -111
- package/lib/graphai.js +140 -322
- package/lib/index.d.ts +2 -0
- package/lib/log.d.ts +22 -0
- package/lib/log.js +49 -0
- package/lib/node.d.ts +50 -0
- package/lib/node.js +218 -0
- package/lib/task.d.ts +18 -0
- package/lib/task.js +63 -0
- package/lib/task_manager.d.ts +20 -0
- package/lib/task_manager.js +69 -0
- package/lib/transaction_log.d.ts +27 -0
- package/lib/transaction_log.js +56 -0
- package/lib/type.d.ts +77 -0
- package/lib/type.js +14 -0
- package/lib/utils/utils.d.ts +4 -0
- package/lib/utils/utils.js +22 -1
- package/lib/validator.d.ts +2 -0
- package/lib/validator.js +28 -0
- package/lib/validators/agent_validator.d.ts +1 -0
- package/lib/validators/agent_validator.js +12 -0
- package/lib/validators/common.d.ts +3 -0
- package/lib/validators/common.js +6 -0
- package/lib/validators/computed_node_validator.d.ts +2 -0
- package/lib/validators/computed_node_validator.js +13 -0
- package/lib/validators/graph_data_validator.d.ts +3 -0
- package/lib/validators/graph_data_validator.js +43 -0
- package/lib/validators/nodeValidator.d.ts +2 -0
- package/lib/validators/nodeValidator.js +13 -0
- package/lib/validators/relation_validator.d.ts +2 -0
- package/lib/validators/relation_validator.js +62 -0
- package/lib/validators/static_node_validator.d.ts +2 -0
- package/lib/validators/static_node_validator.js +13 -0
- package/package.json +3 -5
- package/lib/experimental_agents/array_agents.d.ts +0 -4
- package/lib/experimental_agents/data_agent.d.ts +0 -3
- package/lib/experimental_agents/data_agent.js +0 -25
- package/lib/experimental_agents/sleeper_agent.d.ts +0 -10
- package/lib/experimental_agents/string_agent.d.ts +0 -7
- package/lib/graphai_cli.d.ts +0 -2
- package/lib/graphai_cli.js +0 -37
package/lib/node.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { GraphAI, GraphData } from "./graphai";
|
|
2
|
+
import { NodeDataParams, ResultData, DataSource, ComputedNodeData, StaticNodeData, NodeState } from "./type";
|
|
3
|
+
import { TransactionLog } from "./transaction_log";
|
|
4
|
+
export declare class Node {
|
|
5
|
+
readonly nodeId: string;
|
|
6
|
+
readonly waitlist: Set<string>;
|
|
7
|
+
state: NodeState;
|
|
8
|
+
result: ResultData | undefined;
|
|
9
|
+
protected graph: GraphAI;
|
|
10
|
+
protected log: TransactionLog;
|
|
11
|
+
constructor(nodeId: string, graph: GraphAI);
|
|
12
|
+
asString(): string;
|
|
13
|
+
protected onSetResult(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare class ComputedNode extends Node {
|
|
16
|
+
readonly graphId: string;
|
|
17
|
+
readonly isResult: boolean;
|
|
18
|
+
readonly params: NodeDataParams;
|
|
19
|
+
readonly nestedGraph?: GraphData;
|
|
20
|
+
readonly retryLimit: number;
|
|
21
|
+
retryCount: number;
|
|
22
|
+
readonly agentId?: string;
|
|
23
|
+
readonly timeout?: number;
|
|
24
|
+
error?: Error;
|
|
25
|
+
transactionId: undefined | number;
|
|
26
|
+
sources: Record<string, DataSource>;
|
|
27
|
+
readonly anyInput: boolean;
|
|
28
|
+
inputs: Array<string>;
|
|
29
|
+
pendings: Set<string>;
|
|
30
|
+
readonly isStaticNode = false;
|
|
31
|
+
readonly isComputedNode = true;
|
|
32
|
+
constructor(graphId: string, nodeId: string, data: ComputedNodeData, graph: GraphAI);
|
|
33
|
+
isReadyNode(): boolean;
|
|
34
|
+
private retry;
|
|
35
|
+
removePending(nodeId: string): void;
|
|
36
|
+
private isCurrentTransaction;
|
|
37
|
+
private executeTimeout;
|
|
38
|
+
execute(): Promise<void>;
|
|
39
|
+
private prepareExecute;
|
|
40
|
+
private errorProcess;
|
|
41
|
+
}
|
|
42
|
+
export declare class StaticNode extends Node {
|
|
43
|
+
value?: ResultData;
|
|
44
|
+
readonly update?: string;
|
|
45
|
+
readonly isResult: boolean;
|
|
46
|
+
readonly isStaticNode = true;
|
|
47
|
+
readonly isComputedNode = false;
|
|
48
|
+
constructor(nodeId: string, data: StaticNodeData, graph: GraphAI);
|
|
49
|
+
injectValue(value: ResultData, injectFrom?: string): void;
|
|
50
|
+
}
|
package/lib/node.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
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 transaction_log_1 = require("./transaction_log");
|
|
7
|
+
class Node {
|
|
8
|
+
constructor(nodeId, graph) {
|
|
9
|
+
this.waitlist = new Set(); // List of nodes which need data from this node.
|
|
10
|
+
this.state = type_1.NodeState.Waiting;
|
|
11
|
+
this.result = undefined;
|
|
12
|
+
this.nodeId = nodeId;
|
|
13
|
+
this.graph = graph;
|
|
14
|
+
this.log = new transaction_log_1.TransactionLog(nodeId);
|
|
15
|
+
}
|
|
16
|
+
asString() {
|
|
17
|
+
return `${this.nodeId}: ${this.state} ${[...this.waitlist]}`;
|
|
18
|
+
}
|
|
19
|
+
// This method is called either as the result of computation (computed node) or
|
|
20
|
+
// injection (static node).
|
|
21
|
+
onSetResult() {
|
|
22
|
+
this.waitlist.forEach((waitingNodeId) => {
|
|
23
|
+
const waitingNode = this.graph.nodes[waitingNodeId];
|
|
24
|
+
if (waitingNode.isComputedNode) {
|
|
25
|
+
waitingNode.removePending(this.nodeId);
|
|
26
|
+
this.graph.pushQueueIfReadyAndRunning(waitingNode);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Node = Node;
|
|
32
|
+
class ComputedNode extends Node {
|
|
33
|
+
constructor(graphId, nodeId, data, graph) {
|
|
34
|
+
super(nodeId, graph);
|
|
35
|
+
this.retryCount = 0;
|
|
36
|
+
this.sources = {}; // data sources.
|
|
37
|
+
this.isStaticNode = false;
|
|
38
|
+
this.isComputedNode = true;
|
|
39
|
+
this.graphId = graphId;
|
|
40
|
+
this.params = data.params ?? {};
|
|
41
|
+
this.nestedGraph = data.graph;
|
|
42
|
+
this.agentId = data.agentId;
|
|
43
|
+
this.retryLimit = data.retry ?? 0;
|
|
44
|
+
this.timeout = data.timeout;
|
|
45
|
+
this.isResult = data.isResult ?? false;
|
|
46
|
+
this.anyInput = data.anyInput ?? false;
|
|
47
|
+
this.sources = (data.inputs ?? []).reduce((tmp, input) => {
|
|
48
|
+
const source = (0, utils_1.parseNodeName)(input);
|
|
49
|
+
tmp[source.nodeId] = source;
|
|
50
|
+
return tmp;
|
|
51
|
+
}, {});
|
|
52
|
+
this.inputs = Object.keys(this.sources);
|
|
53
|
+
this.pendings = new Set(this.inputs);
|
|
54
|
+
this.log.initForComputedNode(this);
|
|
55
|
+
}
|
|
56
|
+
isReadyNode() {
|
|
57
|
+
if (this.state === type_1.NodeState.Waiting && this.pendings.size === 0) {
|
|
58
|
+
// Count the number of data actually available.
|
|
59
|
+
// We care it only when this.anyInput is true.
|
|
60
|
+
// Notice that this logic enables dynamic data-flows.
|
|
61
|
+
const counter = this.inputs.reduce((count, nodeId) => {
|
|
62
|
+
const source = this.sources[nodeId];
|
|
63
|
+
const [result] = this.graph.resultsOf([source], this.anyInput);
|
|
64
|
+
return result === undefined ? count : count + 1;
|
|
65
|
+
}, 0);
|
|
66
|
+
if (!this.anyInput || counter > 0) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
// This private method (only called while executing execute()) performs
|
|
73
|
+
// the "retry" if specified. The transaction log must be updated before
|
|
74
|
+
// callling this method.
|
|
75
|
+
retry(state, error) {
|
|
76
|
+
this.state = state; // this.execute() will update to NodeState.Executing
|
|
77
|
+
this.log.onError(this, this.graph, error.message);
|
|
78
|
+
if (this.retryCount < this.retryLimit) {
|
|
79
|
+
this.retryCount++;
|
|
80
|
+
this.execute();
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.result = undefined;
|
|
84
|
+
this.error = error;
|
|
85
|
+
this.transactionId = undefined; // This is necessary for timeout case
|
|
86
|
+
this.graph.onExecutionComplete(this);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// This method is called when the data became available on one of nodes,
|
|
90
|
+
// which this node needs data from.
|
|
91
|
+
removePending(nodeId) {
|
|
92
|
+
if (this.anyInput) {
|
|
93
|
+
const [result] = this.graph.resultsOf([this.sources[nodeId]], this.anyInput);
|
|
94
|
+
if (result) {
|
|
95
|
+
this.pendings.clear();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
this.pendings.delete(nodeId);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
isCurrentTransaction(transactionId) {
|
|
103
|
+
return this.transactionId === transactionId;
|
|
104
|
+
}
|
|
105
|
+
// This private method (called only fro execute) checks if the callback from
|
|
106
|
+
// the timer came before the completion of agent function call, record it
|
|
107
|
+
// and attempt to retry (if specified).
|
|
108
|
+
executeTimeout(transactionId) {
|
|
109
|
+
if (this.state === type_1.NodeState.Executing && this.isCurrentTransaction(transactionId)) {
|
|
110
|
+
console.log(`-- ${this.nodeId}: timeout ${this.timeout}`);
|
|
111
|
+
this.retry(type_1.NodeState.TimedOut, Error("Timeout"));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// This method is called when this computed node became ready to run.
|
|
115
|
+
// It asynchronously calls the associated with agent function and set the result,
|
|
116
|
+
// then it removes itself from the "running node" list of the graph.
|
|
117
|
+
// Notice that setting the result of this node may make other nodes ready to run.
|
|
118
|
+
async execute() {
|
|
119
|
+
const previousResults = this.graph
|
|
120
|
+
.resultsOf(this.inputs.map((input) => {
|
|
121
|
+
return this.sources[input];
|
|
122
|
+
}), this.anyInput)
|
|
123
|
+
.filter((result) => {
|
|
124
|
+
// Remove undefined if anyInput flag is set.
|
|
125
|
+
return !this.anyInput || result !== undefined;
|
|
126
|
+
});
|
|
127
|
+
const transactionId = Date.now();
|
|
128
|
+
this.prepareExecute(transactionId, previousResults);
|
|
129
|
+
if (this.timeout && this.timeout > 0) {
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
this.executeTimeout(transactionId);
|
|
132
|
+
}, this.timeout);
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const callback = this.graph.getCallback(this.agentId);
|
|
136
|
+
const localLog = [];
|
|
137
|
+
const context = {
|
|
138
|
+
params: this.params,
|
|
139
|
+
inputs: previousResults,
|
|
140
|
+
debugInfo: {
|
|
141
|
+
nodeId: this.nodeId,
|
|
142
|
+
retry: this.retryCount,
|
|
143
|
+
verbose: this.graph.verbose,
|
|
144
|
+
},
|
|
145
|
+
log: localLog,
|
|
146
|
+
};
|
|
147
|
+
// NOTE: We use the existence of graph object in the agent-specific params to determine
|
|
148
|
+
// if this is a nested agent or not.
|
|
149
|
+
if (this.nestedGraph) {
|
|
150
|
+
this.graph.taskManager.prepareForNesting();
|
|
151
|
+
context.taskManager = this.graph.taskManager;
|
|
152
|
+
context.graphData = this.nestedGraph;
|
|
153
|
+
context.agents = this.graph.callbackDictonary;
|
|
154
|
+
}
|
|
155
|
+
const result = await callback(context);
|
|
156
|
+
if (this.nestedGraph) {
|
|
157
|
+
this.graph.taskManager.restoreAfterNesting();
|
|
158
|
+
}
|
|
159
|
+
if (!this.isCurrentTransaction(transactionId)) {
|
|
160
|
+
// This condition happens when the agent function returns
|
|
161
|
+
// after the timeout (either retried or not).
|
|
162
|
+
console.log(`-- ${this.nodeId}: transactionId mismatch`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.state = type_1.NodeState.Completed;
|
|
166
|
+
this.result = result;
|
|
167
|
+
this.log.onComplete(this, this.graph, localLog);
|
|
168
|
+
this.onSetResult();
|
|
169
|
+
this.graph.onExecutionComplete(this);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
this.errorProcess(error, transactionId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// This private method (called only by execute()) prepares the ComputedNode object
|
|
176
|
+
// for execution, and create a new transaction to record it.
|
|
177
|
+
prepareExecute(transactionId, inputs) {
|
|
178
|
+
this.state = type_1.NodeState.Executing;
|
|
179
|
+
this.log.beforeExecute(this, this.graph, transactionId, inputs);
|
|
180
|
+
this.transactionId = transactionId;
|
|
181
|
+
}
|
|
182
|
+
// This private method (called only by execute) processes an error received from
|
|
183
|
+
// the agent function. It records the error in the transaction log and handles
|
|
184
|
+
// the retry if specified.
|
|
185
|
+
errorProcess(error, transactionId) {
|
|
186
|
+
console.error(this.agentId + ": error");
|
|
187
|
+
console.error(error);
|
|
188
|
+
if (!this.isCurrentTransaction(transactionId)) {
|
|
189
|
+
console.log(`-- ${this.nodeId}: transactionId mismatch(error)`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (error instanceof Error) {
|
|
193
|
+
this.retry(type_1.NodeState.Failed, error);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.error(`-- ${this.nodeId}: Unexpecrted error was caught`);
|
|
197
|
+
this.retry(type_1.NodeState.Failed, Error("Unknown"));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.ComputedNode = ComputedNode;
|
|
202
|
+
class StaticNode extends Node {
|
|
203
|
+
constructor(nodeId, data, graph) {
|
|
204
|
+
super(nodeId, graph);
|
|
205
|
+
this.isStaticNode = true;
|
|
206
|
+
this.isComputedNode = false;
|
|
207
|
+
this.value = data.value;
|
|
208
|
+
this.update = data.update;
|
|
209
|
+
this.isResult = data.isResult ?? false;
|
|
210
|
+
}
|
|
211
|
+
injectValue(value, injectFrom) {
|
|
212
|
+
this.state = type_1.NodeState.Injected;
|
|
213
|
+
this.result = value;
|
|
214
|
+
this.log.onInjected(this, this.graph, injectFrom);
|
|
215
|
+
this.onSetResult();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.StaticNode = StaticNode;
|
package/lib/task.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ComputedNode } from "./node";
|
|
2
|
+
export declare class TaskManager {
|
|
3
|
+
private concurrency;
|
|
4
|
+
private taskQueue;
|
|
5
|
+
private runningNodes;
|
|
6
|
+
constructor(concurrency: number);
|
|
7
|
+
private dequeueTaskIfPossible;
|
|
8
|
+
addTask(node: ComputedNode, callback: (node: ComputedNode) => void): void;
|
|
9
|
+
onComplete(node: ComputedNode): void;
|
|
10
|
+
prepareForNesting(): void;
|
|
11
|
+
getStatus(verbose?: boolean): {
|
|
12
|
+
runningNodes?: string[] | undefined;
|
|
13
|
+
queuedNodes?: string[] | undefined;
|
|
14
|
+
concurrency: number;
|
|
15
|
+
queue: number;
|
|
16
|
+
running: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
package/lib/task.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskManager = void 0;
|
|
4
|
+
const utils_1 = require("./utils/utils");
|
|
5
|
+
// TaskManage object controls the concurrency of ComputedNode execution.
|
|
6
|
+
//
|
|
7
|
+
// NOTE: A TaskManager instance will be shared between parent graph and its children
|
|
8
|
+
// when nested agents are involved.
|
|
9
|
+
class TaskManager {
|
|
10
|
+
constructor(concurrency) {
|
|
11
|
+
this.taskQueue = [];
|
|
12
|
+
this.runningNodes = new Set();
|
|
13
|
+
this.concurrency = concurrency;
|
|
14
|
+
}
|
|
15
|
+
// This internal method dequeus a task from the task queue
|
|
16
|
+
// and call the associated callback method, if the number of
|
|
17
|
+
// running task is lower than the spcified limit.
|
|
18
|
+
dequeueTaskIfPossible() {
|
|
19
|
+
if (this.runningNodes.size < this.concurrency) {
|
|
20
|
+
const task = this.taskQueue.shift();
|
|
21
|
+
if (task) {
|
|
22
|
+
this.runningNodes.add(task.node);
|
|
23
|
+
task.callback(task.node);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Node will call this method to put itself in the execution queue.
|
|
28
|
+
// We call the associated callback function when it is dequeued.
|
|
29
|
+
addTask(node, callback) {
|
|
30
|
+
this.taskQueue.push({ node, callback });
|
|
31
|
+
this.dequeueTaskIfPossible();
|
|
32
|
+
}
|
|
33
|
+
// Node MUST call this method once the execution of agent function is completed
|
|
34
|
+
// either successfully or not.
|
|
35
|
+
onComplete(node) {
|
|
36
|
+
(0, utils_1.assert)(this.runningNodes.has(node), `TaskManager.onComplete node(${node.nodeId}) is not in list`);
|
|
37
|
+
this.runningNodes.delete(node);
|
|
38
|
+
this.dequeueTaskIfPossible();
|
|
39
|
+
}
|
|
40
|
+
// Node will call this method before it hands the task manager from the graph
|
|
41
|
+
// to a nested agent. We need to make it sure that there is enough room to run
|
|
42
|
+
// computed nodes inside the nested graph to avoid a deadlock.
|
|
43
|
+
prepareForNesting() {
|
|
44
|
+
if (this.runningNodes.size === this.concurrency) {
|
|
45
|
+
this.concurrency++;
|
|
46
|
+
console.warn("WARNING: increasing concurrenty to", this.concurrency);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getStatus(verbose = false) {
|
|
50
|
+
return {
|
|
51
|
+
concurrency: this.concurrency,
|
|
52
|
+
queue: this.taskQueue.length,
|
|
53
|
+
running: this.runningNodes.size,
|
|
54
|
+
...(verbose
|
|
55
|
+
? {
|
|
56
|
+
runningNodes: Array.from(this.runningNodes).map((node) => node.nodeId),
|
|
57
|
+
queuedNodes: this.taskQueue.map((task) => task.node.nodeId),
|
|
58
|
+
}
|
|
59
|
+
: {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.TaskManager = TaskManager;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComputedNode } from "./node";
|
|
2
|
+
export declare class TaskManager {
|
|
3
|
+
private concurrency;
|
|
4
|
+
private taskQueue;
|
|
5
|
+
private runningNodes;
|
|
6
|
+
constructor(concurrency: number);
|
|
7
|
+
private dequeueTaskIfPossible;
|
|
8
|
+
addTask(node: ComputedNode, graphId: string, callback: (node: ComputedNode) => void): void;
|
|
9
|
+
isRunning(graphId: string): boolean;
|
|
10
|
+
onComplete(node: ComputedNode): void;
|
|
11
|
+
prepareForNesting(): void;
|
|
12
|
+
restoreAfterNesting(): void;
|
|
13
|
+
getStatus(verbose?: boolean): {
|
|
14
|
+
runningNodes?: string[] | undefined;
|
|
15
|
+
queuedNodes?: string[] | undefined;
|
|
16
|
+
concurrency: number;
|
|
17
|
+
queue: number;
|
|
18
|
+
running: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TaskManager = void 0;
|
|
4
|
+
const utils_1 = require("./utils/utils");
|
|
5
|
+
// TaskManage object controls the concurrency of ComputedNode execution.
|
|
6
|
+
//
|
|
7
|
+
// NOTE: A TaskManager instance will be shared between parent graph and its children
|
|
8
|
+
// when nested agents are involved.
|
|
9
|
+
class TaskManager {
|
|
10
|
+
constructor(concurrency) {
|
|
11
|
+
this.taskQueue = [];
|
|
12
|
+
this.runningNodes = new Set();
|
|
13
|
+
this.concurrency = concurrency;
|
|
14
|
+
}
|
|
15
|
+
// This internal method dequeus a task from the task queue
|
|
16
|
+
// and call the associated callback method, if the number of
|
|
17
|
+
// running task is lower than the spcified limit.
|
|
18
|
+
dequeueTaskIfPossible() {
|
|
19
|
+
if (this.runningNodes.size < this.concurrency) {
|
|
20
|
+
const task = this.taskQueue.shift();
|
|
21
|
+
if (task) {
|
|
22
|
+
this.runningNodes.add(task.node);
|
|
23
|
+
task.callback(task.node);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Node will call this method to put itself in the execution queue.
|
|
28
|
+
// We call the associated callback function when it is dequeued.
|
|
29
|
+
addTask(node, graphId, callback) {
|
|
30
|
+
this.taskQueue.push({ node, graphId, callback });
|
|
31
|
+
this.dequeueTaskIfPossible();
|
|
32
|
+
}
|
|
33
|
+
isRunning(graphId) {
|
|
34
|
+
const count = [...this.runningNodes].filter((node) => {
|
|
35
|
+
return node.graphId == graphId;
|
|
36
|
+
}).length;
|
|
37
|
+
return count > 0 || Array.from(this.taskQueue).filter((data) => data.graphId === graphId).length > 0;
|
|
38
|
+
}
|
|
39
|
+
// Node MUST call this method once the execution of agent function is completed
|
|
40
|
+
// either successfully or not.
|
|
41
|
+
onComplete(node) {
|
|
42
|
+
(0, utils_1.assert)(this.runningNodes.has(node), `TaskManager.onComplete node(${node.nodeId}) is not in list`);
|
|
43
|
+
this.runningNodes.delete(node);
|
|
44
|
+
this.dequeueTaskIfPossible();
|
|
45
|
+
}
|
|
46
|
+
// Node will call this method before it hands the task manager from the graph
|
|
47
|
+
// to a nested agent. We need to make it sure that there is enough room to run
|
|
48
|
+
// computed nodes inside the nested graph to avoid a deadlock.
|
|
49
|
+
prepareForNesting() {
|
|
50
|
+
this.concurrency++;
|
|
51
|
+
}
|
|
52
|
+
restoreAfterNesting() {
|
|
53
|
+
this.concurrency--;
|
|
54
|
+
}
|
|
55
|
+
getStatus(verbose = false) {
|
|
56
|
+
return {
|
|
57
|
+
concurrency: this.concurrency,
|
|
58
|
+
queue: this.taskQueue.length,
|
|
59
|
+
running: this.runningNodes.size,
|
|
60
|
+
...(verbose
|
|
61
|
+
? {
|
|
62
|
+
runningNodes: Array.from(this.runningNodes).map((node) => node.nodeId),
|
|
63
|
+
queuedNodes: this.taskQueue.map((task) => task.node.nodeId),
|
|
64
|
+
}
|
|
65
|
+
: {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.TaskManager = TaskManager;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ResultData, NodeDataParams, NodeState } from "./type";
|
|
2
|
+
import type { GraphAI } from "./graphai";
|
|
3
|
+
import type { ComputedNode, StaticNode } from "./node";
|
|
4
|
+
export declare class TransactionLog {
|
|
5
|
+
nodeId: string;
|
|
6
|
+
state: NodeState;
|
|
7
|
+
startTime?: number;
|
|
8
|
+
endTime?: number;
|
|
9
|
+
retryCount?: number;
|
|
10
|
+
agentId?: string;
|
|
11
|
+
params?: NodeDataParams;
|
|
12
|
+
inputs?: string[];
|
|
13
|
+
inputsData?: Array<ResultData>;
|
|
14
|
+
injectFrom?: string;
|
|
15
|
+
errorMessage?: string;
|
|
16
|
+
result?: ResultData;
|
|
17
|
+
mapIndex?: number;
|
|
18
|
+
isLoop?: boolean;
|
|
19
|
+
repeatCount?: number;
|
|
20
|
+
log?: TransactionLog[];
|
|
21
|
+
constructor(nodeId: string);
|
|
22
|
+
initForComputedNode(node: ComputedNode): void;
|
|
23
|
+
onInjected(node: StaticNode, graph: GraphAI, injectFrom?: string): void;
|
|
24
|
+
onComplete(node: ComputedNode, graph: GraphAI, localLog: TransactionLog[]): void;
|
|
25
|
+
beforeExecute(node: ComputedNode, graph: GraphAI, transactionId: number, inputs: ResultData[]): void;
|
|
26
|
+
onError(node: ComputedNode, graph: GraphAI, errorMessage: string): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransactionLog = void 0;
|
|
4
|
+
const type_1 = require("./type");
|
|
5
|
+
class TransactionLog {
|
|
6
|
+
constructor(nodeId) {
|
|
7
|
+
this.nodeId = nodeId;
|
|
8
|
+
this.state = type_1.NodeState.Waiting;
|
|
9
|
+
}
|
|
10
|
+
initForComputedNode(node) {
|
|
11
|
+
this.agentId = node.agentId;
|
|
12
|
+
this.params = node.params;
|
|
13
|
+
}
|
|
14
|
+
onInjected(node, graph, injectFrom) {
|
|
15
|
+
const isUpdating = "endTime" in this;
|
|
16
|
+
this.result = node.result;
|
|
17
|
+
this.state = node.state;
|
|
18
|
+
this.endTime = Date.now();
|
|
19
|
+
this.injectFrom = injectFrom;
|
|
20
|
+
graph.setLoopLog(this);
|
|
21
|
+
// console.log(this)
|
|
22
|
+
if (isUpdating) {
|
|
23
|
+
graph.updateLog(this);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
graph.appendLog(this);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
onComplete(node, graph, localLog) {
|
|
30
|
+
this.result = node.result;
|
|
31
|
+
this.state = node.state;
|
|
32
|
+
this.endTime = Date.now();
|
|
33
|
+
graph.setLoopLog(this);
|
|
34
|
+
if (localLog.length > 0) {
|
|
35
|
+
this.log = localLog;
|
|
36
|
+
}
|
|
37
|
+
graph.updateLog(this);
|
|
38
|
+
}
|
|
39
|
+
beforeExecute(node, graph, transactionId, inputs) {
|
|
40
|
+
this.state = node.state;
|
|
41
|
+
this.retryCount = node.retryCount > 0 ? node.retryCount : undefined;
|
|
42
|
+
this.startTime = transactionId;
|
|
43
|
+
this.inputs = node.inputs;
|
|
44
|
+
this.inputsData = inputs.length > 0 ? inputs : undefined;
|
|
45
|
+
graph.setLoopLog(this);
|
|
46
|
+
graph.appendLog(this);
|
|
47
|
+
}
|
|
48
|
+
onError(node, graph, errorMessage) {
|
|
49
|
+
this.state = node.state;
|
|
50
|
+
this.errorMessage = errorMessage;
|
|
51
|
+
this.endTime = Date.now();
|
|
52
|
+
graph.setLoopLog(this);
|
|
53
|
+
graph.updateLog(this);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.TransactionLog = TransactionLog;
|
package/lib/type.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { TransactionLog } from "./transaction_log";
|
|
2
|
+
import type { TaskManager } from "./task_manager";
|
|
3
|
+
export declare enum NodeState {
|
|
4
|
+
Waiting = "waiting",
|
|
5
|
+
Queued = "queued",
|
|
6
|
+
Executing = "executing",
|
|
7
|
+
Failed = "failed",
|
|
8
|
+
TimedOut = "timed-out",
|
|
9
|
+
Completed = "completed",
|
|
10
|
+
Injected = "injected",
|
|
11
|
+
Dispatched = "dispatched"
|
|
12
|
+
}
|
|
13
|
+
export type DefaultResultData = Record<string, any>;
|
|
14
|
+
export type DefaultInputData = Record<string, any>;
|
|
15
|
+
export type ResultData<ResultType = DefaultResultData> = ResultType | undefined;
|
|
16
|
+
export type ResultDataDictonary<ResultType = DefaultResultData> = Record<string, ResultData<ResultType>>;
|
|
17
|
+
export type DefaultParamsType = Record<string, any>;
|
|
18
|
+
export type NodeDataParams<ParamsType = DefaultParamsType> = ParamsType;
|
|
19
|
+
export type DataSource = {
|
|
20
|
+
nodeId: string;
|
|
21
|
+
propId?: string;
|
|
22
|
+
};
|
|
23
|
+
export type StaticNodeData = {
|
|
24
|
+
value: ResultData;
|
|
25
|
+
update?: string;
|
|
26
|
+
isResult?: boolean;
|
|
27
|
+
};
|
|
28
|
+
export type ComputedNodeData = {
|
|
29
|
+
agentId: string;
|
|
30
|
+
inputs?: Array<string>;
|
|
31
|
+
anyInput?: boolean;
|
|
32
|
+
params?: NodeDataParams;
|
|
33
|
+
retry?: number;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
graph?: GraphData;
|
|
36
|
+
isResult?: boolean;
|
|
37
|
+
};
|
|
38
|
+
export type NodeData = StaticNodeData | ComputedNodeData;
|
|
39
|
+
export type LoopData = {
|
|
40
|
+
count?: number;
|
|
41
|
+
while?: string;
|
|
42
|
+
};
|
|
43
|
+
export type GraphData = {
|
|
44
|
+
nodes: Record<string, NodeData>;
|
|
45
|
+
concurrency?: number;
|
|
46
|
+
loop?: LoopData;
|
|
47
|
+
verbose?: boolean;
|
|
48
|
+
};
|
|
49
|
+
export type AgentFunctionContext<ParamsType, InputDataType> = {
|
|
50
|
+
params: NodeDataParams<ParamsType>;
|
|
51
|
+
inputs: Array<InputDataType>;
|
|
52
|
+
debugInfo: {
|
|
53
|
+
verbose: boolean;
|
|
54
|
+
nodeId: string;
|
|
55
|
+
retry: number;
|
|
56
|
+
};
|
|
57
|
+
graphData?: GraphData;
|
|
58
|
+
agents?: AgentFunctionDictonary;
|
|
59
|
+
log?: TransactionLog[];
|
|
60
|
+
taskManager?: TaskManager;
|
|
61
|
+
};
|
|
62
|
+
export type AgentFunction<ParamsType = DefaultParamsType, ResultType = DefaultResultData, InputDataType = DefaultInputData> = (context: AgentFunctionContext<ParamsType, InputDataType>) => Promise<ResultData<ResultType>>;
|
|
63
|
+
export type AgentFunctionDictonary = Record<string, AgentFunction<any, any, any>>;
|
|
64
|
+
export type AgentFunctionInfo = {
|
|
65
|
+
name: string;
|
|
66
|
+
agent: AgentFunction<any, any, any>;
|
|
67
|
+
mock: AgentFunction<any, any, any>;
|
|
68
|
+
samples: {
|
|
69
|
+
inputs: any;
|
|
70
|
+
params: DefaultParamsType;
|
|
71
|
+
result: any;
|
|
72
|
+
}[];
|
|
73
|
+
description: string;
|
|
74
|
+
author: string;
|
|
75
|
+
repository: string;
|
|
76
|
+
license: string;
|
|
77
|
+
};
|
package/lib/type.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
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["Queued"] = "queued";
|
|
8
|
+
NodeState["Executing"] = "executing";
|
|
9
|
+
NodeState["Failed"] = "failed";
|
|
10
|
+
NodeState["TimedOut"] = "timed-out";
|
|
11
|
+
NodeState["Completed"] = "completed";
|
|
12
|
+
NodeState["Injected"] = "injected";
|
|
13
|
+
NodeState["Dispatched"] = "dispatched";
|
|
14
|
+
})(NodeState || (exports.NodeState = NodeState = {}));
|
package/lib/utils/utils.d.ts
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
+
import { DataSource } from "../type";
|
|
1
2
|
export declare const sleep: (milliseconds: number) => Promise<unknown>;
|
|
3
|
+
export declare const parseNodeName: (inputNodeId: string) => DataSource;
|
|
4
|
+
export declare function assert(condition: boolean, message: string, isWarn?: boolean): asserts condition;
|
|
5
|
+
export declare const isObject: (x: unknown) => boolean;
|
package/lib/utils/utils.js
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sleep = void 0;
|
|
3
|
+
exports.isObject = exports.assert = 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 = (inputNodeId) => {
|
|
9
|
+
const parts = inputNodeId.split(".");
|
|
10
|
+
if (parts.length == 1) {
|
|
11
|
+
return { nodeId: parts[0] };
|
|
12
|
+
}
|
|
13
|
+
return { nodeId: parts[0], propId: parts[1] };
|
|
14
|
+
};
|
|
15
|
+
exports.parseNodeName = parseNodeName;
|
|
16
|
+
function assert(condition, message, isWarn = false) {
|
|
17
|
+
if (!condition) {
|
|
18
|
+
if (!isWarn) {
|
|
19
|
+
throw new Error(message);
|
|
20
|
+
}
|
|
21
|
+
console.warn("warn: " + message);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.assert = assert;
|
|
25
|
+
const isObject = (x) => {
|
|
26
|
+
return x !== null && typeof x === "object";
|
|
27
|
+
};
|
|
28
|
+
exports.isObject = isObject;
|