graphai 0.5.8 → 0.5.10
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 +41 -20
- package/lib/graphai.d.ts +5 -7
- package/lib/graphai.js +30 -23
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -1
- package/lib/node.d.ts +8 -5
- package/lib/node.js +58 -64
- package/lib/result.d.ts +6 -0
- package/lib/result.js +69 -0
- package/lib/transaction_log.js +1 -1
- package/lib/type.d.ts +2 -3
- package/lib/utils/nodeUtils.d.ts +3 -5
- package/lib/utils/nodeUtils.js +21 -43
- package/lib/utils/utils.d.ts +4 -2
- package/lib/utils/utils.js +58 -21
- package/lib/validators/relation_validator.js +28 -27
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -22,41 +22,53 @@ nodes:
|
|
|
22
22
|
query: describe the final sentence by the court for Sam Bank-Fried
|
|
23
23
|
wikipedia: // Retrieve data from Wikipedia
|
|
24
24
|
agent: wikipediaAgent
|
|
25
|
-
inputs:
|
|
25
|
+
inputs:
|
|
26
|
+
query: :source.name
|
|
26
27
|
chunks: // Break the text from Wikipedia into chunks (2048 character each with 512 overlap)
|
|
27
28
|
agent: stringSplitterAgent
|
|
28
|
-
inputs:
|
|
29
|
+
inputs:
|
|
30
|
+
text: :wikipedia
|
|
29
31
|
chunkEmbeddings: // Get embedding vector of each chunk
|
|
30
32
|
agent: stringEmbeddingsAgent
|
|
31
|
-
inputs:
|
|
33
|
+
inputs:
|
|
34
|
+
array: :chunks
|
|
32
35
|
topicEmbedding: // Get embedding vector of the question
|
|
33
36
|
agent: stringEmbeddingsAgent
|
|
34
|
-
inputs:
|
|
37
|
+
inputs:
|
|
38
|
+
item: :source.query
|
|
35
39
|
similarities: // Calculate the cosine similarity of each chunk
|
|
36
40
|
agent: dotProductAgent
|
|
37
|
-
inputs:
|
|
41
|
+
inputs:
|
|
42
|
+
matrix: :chunkEmbeddings
|
|
43
|
+
vector: :topicEmbedding
|
|
38
44
|
sortedChunks: // Sort chunks based on their similarities
|
|
39
45
|
agent: sortByValuesAgent
|
|
40
|
-
inputs:
|
|
46
|
+
inputs:
|
|
47
|
+
array: :chunks
|
|
48
|
+
values: :similarities
|
|
41
49
|
referenceText: // Concatenate chunks up to the token limit (5000)
|
|
42
50
|
agent: tokenBoundStringsAgent
|
|
43
|
-
inputs:
|
|
51
|
+
inputs:
|
|
52
|
+
array: :sortedChunks
|
|
44
53
|
params:
|
|
45
54
|
limit: 5000
|
|
46
55
|
prompt: // Generate a prompt with that reference text
|
|
47
56
|
agent: stringTemplateAgent
|
|
48
|
-
inputs:
|
|
57
|
+
inputs:
|
|
58
|
+
prompt: :source
|
|
59
|
+
text: :referenceText
|
|
49
60
|
params:
|
|
50
61
|
template: |-
|
|
51
|
-
Using the following document, ${
|
|
52
|
-
${
|
|
62
|
+
Using the following document, ${prompt}
|
|
63
|
+
${text}
|
|
53
64
|
query: // retrieves the answer from GPT3.5
|
|
54
65
|
agent: slashGPTAgent
|
|
55
66
|
params:
|
|
56
67
|
manifest:
|
|
57
68
|
model: gpt-3.5-turbo
|
|
58
69
|
isResult: true // indicating this is the final result
|
|
59
|
-
inputs:
|
|
70
|
+
inputs:
|
|
71
|
+
prompt: :prompt
|
|
60
72
|
```
|
|
61
73
|
|
|
62
74
|
```mermaid
|
|
@@ -134,8 +146,10 @@ Here is an examnple (from [weather chat](https://github.com/receptron/graphai/bl
|
|
|
134
146
|
```typescript
|
|
135
147
|
messagesWithUserInput: {
|
|
136
148
|
// Appends the user's input to the messages.
|
|
137
|
-
agent: (messages: Array<any>, content: string) => [...messages, { role: "user", content }],
|
|
138
|
-
inputs:
|
|
149
|
+
agent: ({ messages: Array<any>, content: string }) => [...messages, { role: "user", content }],
|
|
150
|
+
inputs:
|
|
151
|
+
messages: ":messages"
|
|
152
|
+
content: ":userInput"
|
|
139
153
|
if: "checkInput",
|
|
140
154
|
},
|
|
141
155
|
```
|
|
@@ -186,8 +200,9 @@ nodes:
|
|
|
186
200
|
question:
|
|
187
201
|
value: "Find out which materials we need to purchase this week for Joe Smith's residential house project."
|
|
188
202
|
projectId: // identifies the projectId from the question
|
|
189
|
-
agent:
|
|
190
|
-
inputs:
|
|
203
|
+
agent: identifierAgent
|
|
204
|
+
inputs:
|
|
205
|
+
id: :source
|
|
191
206
|
database:
|
|
192
207
|
agent: "nestedAgent"
|
|
193
208
|
inputs:
|
|
@@ -201,11 +216,13 @@ nodes:
|
|
|
201
216
|
... // issue query to the database and build an appropriate prompt with it.
|
|
202
217
|
query: // send the generated prompt to the LLM
|
|
203
218
|
agent: "llama3Agent"
|
|
204
|
-
inputs:
|
|
219
|
+
inputs:
|
|
220
|
+
promot: ":prompt"
|
|
205
221
|
isResult: true
|
|
206
222
|
response: // Deliver the answer
|
|
207
223
|
agent: "deliveryAgent"
|
|
208
|
-
inputs:
|
|
224
|
+
inputs:
|
|
225
|
+
text: :database.query.$last.content
|
|
209
226
|
```
|
|
210
227
|
|
|
211
228
|
The databaseQuery node (which is associated "nestedAgent") takes the data from "question" node abd "projectId" node, and make them available to inner nodes (nodes of the child graph) via phantom node, "$0" and "$1". After the completion of the child graph, the data from "query" node (which has "isResult" property) becomes available as a property of the output of "database" node.
|
|
@@ -256,7 +273,8 @@ nodes:
|
|
|
256
273
|
isResult: true
|
|
257
274
|
retriever:
|
|
258
275
|
agent: shift
|
|
259
|
-
inputs:
|
|
276
|
+
inputs:
|
|
277
|
+
array: :people
|
|
260
278
|
query:
|
|
261
279
|
agent: slashgpt
|
|
262
280
|
params:
|
|
@@ -265,7 +283,9 @@ nodes:
|
|
|
265
283
|
inputs: [:retriever.item]
|
|
266
284
|
reducer:
|
|
267
285
|
agent: push
|
|
268
|
-
inputs:
|
|
286
|
+
inputs:
|
|
287
|
+
array: :result
|
|
288
|
+
item: :query.content
|
|
269
289
|
```
|
|
270
290
|
|
|
271
291
|
```mermaid
|
|
@@ -353,7 +373,8 @@ This property is particularly useful when you want to continue the flow regardle
|
|
|
353
373
|
// Receives messages from either case.
|
|
354
374
|
agent: "copyAgent",
|
|
355
375
|
anyInput: true,
|
|
356
|
-
inputs:
|
|
376
|
+
inputs:
|
|
377
|
+
array: [":no_tool_calls", ":tool_calls.messagesWithSecondRes"],
|
|
357
378
|
},
|
|
358
379
|
```
|
|
359
380
|
|
package/lib/graphai.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { AgentFunctionInfoDictionary, AgentFilterInfo, GraphData, DataSource, ResultDataDictionary, ResultData, DefaultResultData, GraphOptions
|
|
1
|
+
import { AgentFunctionInfoDictionary, AgentFilterInfo, GraphData, DataSource, ResultDataDictionary, ResultData, DefaultResultData, GraphOptions } from "./type";
|
|
2
2
|
import { TransactionLog } from "./transaction_log";
|
|
3
|
-
import { ComputedNode,
|
|
3
|
+
import { ComputedNode, GraphNodes } from "./node";
|
|
4
4
|
import { TaskManager } from "./task_manager";
|
|
5
|
-
type GraphNodes = Record<string, ComputedNode | StaticNode>;
|
|
6
5
|
export declare const defaultConcurrency = 8;
|
|
7
6
|
export declare const graphDataLatestVersion = 0.5;
|
|
8
7
|
export declare class GraphAI {
|
|
@@ -24,7 +23,8 @@ export declare class GraphAI {
|
|
|
24
23
|
private repeatCount;
|
|
25
24
|
private createNodes;
|
|
26
25
|
private getValueFromResults;
|
|
27
|
-
private
|
|
26
|
+
private initializeStaticNodes;
|
|
27
|
+
private updateStaticNodes;
|
|
28
28
|
constructor(data: GraphData, agentFunctionInfoDictionary: AgentFunctionInfoDictionary, options?: GraphOptions);
|
|
29
29
|
getAgentFunctionInfo(agentId?: string): import("./type").AgentFunctionInfo | {
|
|
30
30
|
agent: () => Promise<null>;
|
|
@@ -46,8 +46,6 @@ export declare class GraphAI {
|
|
|
46
46
|
updateLog(log: TransactionLog): void;
|
|
47
47
|
transactionLogs(): TransactionLog[];
|
|
48
48
|
injectValue(nodeId: string, value: ResultData, injectFrom?: string): void;
|
|
49
|
-
|
|
50
|
-
resultsOf(sources: NestedDataSource): Record<string, ResultData>;
|
|
49
|
+
resultsOf(inputs?: Array<any> | Record<string, any>, anyInput?: boolean): Record<string, ResultData>;
|
|
51
50
|
resultOf(source: DataSource): ResultData;
|
|
52
51
|
}
|
|
53
|
-
export {};
|
package/lib/graphai.js
CHANGED
|
@@ -5,6 +5,7 @@ const node_1 = require("./node");
|
|
|
5
5
|
const utils_1 = require("./utils/utils");
|
|
6
6
|
const validator_1 = require("./validator");
|
|
7
7
|
const task_manager_1 = require("./task_manager");
|
|
8
|
+
const result_1 = require("./result");
|
|
8
9
|
exports.defaultConcurrency = 8;
|
|
9
10
|
exports.graphDataLatestVersion = 0.5;
|
|
10
11
|
class GraphAI {
|
|
@@ -44,7 +45,7 @@ class GraphAI {
|
|
|
44
45
|
return (0, utils_1.getDataFromSource)(source.nodeId ? results[source.nodeId] : undefined, source);
|
|
45
46
|
}
|
|
46
47
|
// for static
|
|
47
|
-
|
|
48
|
+
initializeStaticNodes() {
|
|
48
49
|
// If the result property is specified, inject it.
|
|
49
50
|
// If the previousResults exists (indicating we are in a loop),
|
|
50
51
|
// process the update property (nodeId or nodeId.propId).
|
|
@@ -55,6 +56,16 @@ class GraphAI {
|
|
|
55
56
|
if (value !== undefined) {
|
|
56
57
|
this.injectValue(nodeId, value, nodeId);
|
|
57
58
|
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
updateStaticNodes(previousResults) {
|
|
63
|
+
// If the result property is specified, inject it.
|
|
64
|
+
// If the previousResults exists (indicating we are in a loop),
|
|
65
|
+
// process the update property (nodeId or nodeId.propId).
|
|
66
|
+
Object.keys(this.data.nodes).forEach((nodeId) => {
|
|
67
|
+
const node = this.nodes[nodeId];
|
|
68
|
+
if (node?.isStaticNode) {
|
|
58
69
|
const update = node?.update;
|
|
59
70
|
if (update && previousResults) {
|
|
60
71
|
const result = this.getValueFromResults(update, previousResults);
|
|
@@ -95,7 +106,7 @@ class GraphAI {
|
|
|
95
106
|
};
|
|
96
107
|
(0, validator_1.validateGraphData)(data, [...Object.keys(agentFunctionInfoDictionary), ...this.bypassAgentIds]);
|
|
97
108
|
this.nodes = this.createNodes(data);
|
|
98
|
-
this.
|
|
109
|
+
this.initializeStaticNodes();
|
|
99
110
|
}
|
|
100
111
|
getAgentFunctionInfo(agentId) {
|
|
101
112
|
if (agentId && this.agentFunctionInfoDictionary[agentId]) {
|
|
@@ -209,19 +220,24 @@ class GraphAI {
|
|
|
209
220
|
processLoopIfNecessary() {
|
|
210
221
|
this.repeatCount++;
|
|
211
222
|
const loop = this.loop;
|
|
212
|
-
if (loop
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
223
|
+
if (!loop) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
// We need to update static nodes, before checking the condition
|
|
227
|
+
const previousResults = this.results(true); // results from previous loop
|
|
228
|
+
this.updateStaticNodes(previousResults);
|
|
229
|
+
if (loop.count === undefined || this.repeatCount < loop.count) {
|
|
217
230
|
if (loop.while) {
|
|
218
|
-
const source = (0, utils_1.parseNodeName)(loop.while
|
|
231
|
+
const source = (0, utils_1.parseNodeName)(loop.while);
|
|
219
232
|
const value = this.getValueFromResults(source, this.results(true));
|
|
220
233
|
// NOTE: We treat an empty array as false.
|
|
221
234
|
if (!(0, utils_1.isLogicallyTrue)(value)) {
|
|
222
235
|
return false; // while condition is not met
|
|
223
236
|
}
|
|
224
237
|
}
|
|
238
|
+
this.nodes = this.createNodes(this.data);
|
|
239
|
+
this.initializeStaticNodes();
|
|
240
|
+
this.updateStaticNodes(previousResults);
|
|
225
241
|
this.pushReadyNodesIntoQueue();
|
|
226
242
|
return true; // Indicating that we are going to continue.
|
|
227
243
|
}
|
|
@@ -252,24 +268,15 @@ class GraphAI {
|
|
|
252
268
|
throw new Error(`injectValue with Invalid nodeId, ${nodeId}`);
|
|
253
269
|
}
|
|
254
270
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
});
|
|
271
|
+
resultsOf(inputs, anyInput = false) {
|
|
272
|
+
const results = (0, result_1.resultsOf)(inputs ?? [], this.nodes);
|
|
273
|
+
if (anyInput) {
|
|
274
|
+
return (0, result_1.cleanResult)(results);
|
|
260
275
|
}
|
|
261
|
-
return
|
|
262
|
-
}
|
|
263
|
-
resultsOf(sources) {
|
|
264
|
-
const ret = {};
|
|
265
|
-
Object.keys(sources).forEach((key) => {
|
|
266
|
-
ret[key] = this.nestedResultOf(sources[key]);
|
|
267
|
-
});
|
|
268
|
-
return ret;
|
|
276
|
+
return results;
|
|
269
277
|
}
|
|
270
278
|
resultOf(source) {
|
|
271
|
-
|
|
272
|
-
return (0, utils_1.getDataFromSource)(result, source);
|
|
279
|
+
return (0, result_1.resultOf)(source, this.nodes);
|
|
273
280
|
}
|
|
274
281
|
}
|
|
275
282
|
exports.GraphAI = GraphAI;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { GraphAI, defaultConcurrency, graphDataLatestVersion } from "./graphai";
|
|
2
|
-
export { AgentFunction, AgentFunctionInfo, AgentFunctionInfoDictionary, AgentFunctionInfoSample, AgentFunctionContext, GraphData, ResultDataDictionary, ResultData, NodeState, AgentFilterFunction, AgentFilterInfo, NodeData, StaticNodeData, ComputedNodeData, DefaultResultData, DefaultInputData, } from "./type";
|
|
2
|
+
export { AgentFunction, AgentFunctionInfo, AgentFunctionInfoDictionary, AgentFunctionInfoSample, AgentFunctionContext, GraphData, ResultDataDictionary, ResultData, NodeState, AgentFilterFunction, AgentFilterInfo, NodeData, StaticNodeData, ComputedNodeData, DefaultResultData, DefaultInputData, DefaultParamsType, } from "./type";
|
|
3
3
|
export type { TransactionLog } from "./transaction_log";
|
|
4
|
-
export { defaultAgentInfo, agentInfoWrapper, defaultTestContext, strIntentionalError, assert, sleep } from "./utils/utils";
|
|
4
|
+
export { defaultAgentInfo, agentInfoWrapper, defaultTestContext, strIntentionalError, assert, sleep, isObject } from "./utils/utils";
|
|
5
5
|
export { ValidationError } from "./validators/common";
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ValidationError = exports.sleep = exports.assert = exports.strIntentionalError = exports.defaultTestContext = exports.agentInfoWrapper = exports.defaultAgentInfo = exports.NodeState = exports.graphDataLatestVersion = exports.defaultConcurrency = exports.GraphAI = void 0;
|
|
3
|
+
exports.ValidationError = exports.isObject = exports.sleep = exports.assert = exports.strIntentionalError = exports.defaultTestContext = exports.agentInfoWrapper = exports.defaultAgentInfo = exports.NodeState = exports.graphDataLatestVersion = exports.defaultConcurrency = exports.GraphAI = void 0;
|
|
4
4
|
var graphai_1 = require("./graphai");
|
|
5
5
|
Object.defineProperty(exports, "GraphAI", { enumerable: true, get: function () { return graphai_1.GraphAI; } });
|
|
6
6
|
Object.defineProperty(exports, "defaultConcurrency", { enumerable: true, get: function () { return graphai_1.defaultConcurrency; } });
|
|
@@ -14,5 +14,6 @@ Object.defineProperty(exports, "defaultTestContext", { enumerable: true, get: fu
|
|
|
14
14
|
Object.defineProperty(exports, "strIntentionalError", { enumerable: true, get: function () { return utils_1.strIntentionalError; } });
|
|
15
15
|
Object.defineProperty(exports, "assert", { enumerable: true, get: function () { return utils_1.assert; } });
|
|
16
16
|
Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return utils_1.sleep; } });
|
|
17
|
+
Object.defineProperty(exports, "isObject", { enumerable: true, get: function () { return utils_1.isObject; } });
|
|
17
18
|
var common_1 = require("./validators/common");
|
|
18
19
|
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return common_1.ValidationError; } });
|
package/lib/node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GraphAI, GraphData } from "./index";
|
|
2
|
-
import { NodeDataParams, ResultData, DataSource, ComputedNodeData, StaticNodeData, NodeState
|
|
2
|
+
import { NodeDataParams, ResultData, DataSource, ComputedNodeData, StaticNodeData, NodeState } from "./type";
|
|
3
3
|
import { TransactionLog } from "./transaction_log";
|
|
4
4
|
export declare class Node {
|
|
5
5
|
readonly nodeId: string;
|
|
@@ -29,9 +29,9 @@ export declare class ComputedNode extends Node {
|
|
|
29
29
|
transactionId: undefined | number;
|
|
30
30
|
private readonly passThrough?;
|
|
31
31
|
readonly anyInput: boolean;
|
|
32
|
-
dataSources:
|
|
32
|
+
dataSources: DataSource[];
|
|
33
33
|
private inputs?;
|
|
34
|
-
|
|
34
|
+
isNamedInputs: boolean;
|
|
35
35
|
pendings: Set<string>;
|
|
36
36
|
private ifSource?;
|
|
37
37
|
private unlessSource?;
|
|
@@ -40,7 +40,7 @@ export declare class ComputedNode extends Node {
|
|
|
40
40
|
readonly isComputedNode = true;
|
|
41
41
|
constructor(graphId: string, nodeId: string, data: ComputedNodeData, graph: GraphAI);
|
|
42
42
|
getAgentId(): string;
|
|
43
|
-
private
|
|
43
|
+
private addPendingNode;
|
|
44
44
|
isReadyNode(): boolean;
|
|
45
45
|
private retry;
|
|
46
46
|
private checkDataAvailability;
|
|
@@ -53,8 +53,10 @@ export declare class ComputedNode extends Node {
|
|
|
53
53
|
execute(): Promise<void>;
|
|
54
54
|
private prepareExecute;
|
|
55
55
|
private errorProcess;
|
|
56
|
-
private
|
|
56
|
+
private getParams;
|
|
57
57
|
private getInputs;
|
|
58
|
+
private getContext;
|
|
59
|
+
private getResult;
|
|
58
60
|
private getDebugInfo;
|
|
59
61
|
private beforeConsoleLog;
|
|
60
62
|
private afterConsoleLog;
|
|
@@ -68,3 +70,4 @@ export declare class StaticNode extends Node {
|
|
|
68
70
|
constructor(nodeId: string, data: StaticNodeData, graph: GraphAI);
|
|
69
71
|
injectValue(value: ResultData, injectFrom?: string): void;
|
|
70
72
|
}
|
|
73
|
+
export type GraphNodes = Record<string, ComputedNode | StaticNode>;
|
package/lib/node.js
CHANGED
|
@@ -35,7 +35,8 @@ class ComputedNode extends Node {
|
|
|
35
35
|
constructor(graphId, nodeId, data, graph) {
|
|
36
36
|
super(nodeId, graph);
|
|
37
37
|
this.retryCount = 0;
|
|
38
|
-
this.dataSources =
|
|
38
|
+
this.dataSources = []; // no longer needed. This is for transaction log.
|
|
39
|
+
this.isNamedInputs = false;
|
|
39
40
|
this.isStaticNode = false;
|
|
40
41
|
this.isComputedNode = true;
|
|
41
42
|
this.graphId = graphId;
|
|
@@ -48,36 +49,32 @@ class ComputedNode extends Node {
|
|
|
48
49
|
this.isResult = data.isResult ?? false;
|
|
49
50
|
this.priority = data.priority ?? 0;
|
|
50
51
|
this.anyInput = data.anyInput ?? false;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
this.inputNames = Object.keys(data.inputs);
|
|
58
|
-
this.dataSources = (0, nodeUtils_1.namedInputs2dataSources)(data.inputs, graph.version);
|
|
59
|
-
}
|
|
52
|
+
this.inputs = data.inputs;
|
|
53
|
+
this.isNamedInputs = (0, utils_2.isObject)(data.inputs) && !Array.isArray(data.inputs);
|
|
54
|
+
this.dataSources = data.inputs ? (0, nodeUtils_1.inputs2dataSources)(data.inputs).flat(10) : [];
|
|
55
|
+
if (data.inputs && !this.isNamedInputs) {
|
|
56
|
+
console.warn(`array inputs have been deprecated. nodeId: ${nodeId}: see https://github.com/receptron/graphai/blob/main/docs/NamedInputs.md`);
|
|
60
57
|
}
|
|
61
|
-
this.pendings = new Set((0, nodeUtils_1.
|
|
58
|
+
this.pendings = new Set((0, nodeUtils_1.dataSourceNodeIds)(this.dataSources));
|
|
62
59
|
(0, utils_2.assert)(["function", "string"].includes(typeof data.agent), "agent must be either string or function");
|
|
63
60
|
if (typeof data.agent === "string") {
|
|
64
61
|
this.agentId = data.agent;
|
|
65
62
|
}
|
|
66
63
|
else {
|
|
67
64
|
const agent = data.agent;
|
|
68
|
-
this.agentFunction = this.
|
|
65
|
+
this.agentFunction = this.isNamedInputs ? async ({ namedInputs }) => agent(namedInputs) : async ({ inputs }) => agent(...inputs);
|
|
69
66
|
}
|
|
70
67
|
if (data.graph) {
|
|
71
|
-
this.nestedGraph = typeof data.graph === "string" ? this.
|
|
68
|
+
this.nestedGraph = typeof data.graph === "string" ? this.addPendingNode(data.graph) : data.graph;
|
|
72
69
|
}
|
|
73
70
|
if (data.if) {
|
|
74
|
-
this.ifSource = this.
|
|
71
|
+
this.ifSource = this.addPendingNode(data.if);
|
|
75
72
|
}
|
|
76
73
|
if (data.unless) {
|
|
77
|
-
this.unlessSource = this.
|
|
74
|
+
this.unlessSource = this.addPendingNode(data.unless);
|
|
78
75
|
}
|
|
79
76
|
this.dynamicParams = Object.keys(this.params).reduce((tmp, key) => {
|
|
80
|
-
const dataSource = (0, utils_2.parseNodeName)(this.params[key]
|
|
77
|
+
const dataSource = (0, utils_2.parseNodeName)(this.params[key]);
|
|
81
78
|
if (dataSource.nodeId) {
|
|
82
79
|
(0, utils_2.assert)(!this.anyInput, "Dynamic params are not supported with anyInput");
|
|
83
80
|
tmp[key] = dataSource;
|
|
@@ -90,8 +87,8 @@ class ComputedNode extends Node {
|
|
|
90
87
|
getAgentId() {
|
|
91
88
|
return this.agentId ?? "__custom__function"; // only for display purpose in the log.
|
|
92
89
|
}
|
|
93
|
-
|
|
94
|
-
const source = (0, utils_2.parseNodeName)(nodeId
|
|
90
|
+
addPendingNode(nodeId) {
|
|
91
|
+
const source = (0, utils_2.parseNodeName)(nodeId);
|
|
95
92
|
(0, utils_2.assert)(!!source.nodeId, `Invalid data source ${nodeId}`);
|
|
96
93
|
this.pendings.add(source.nodeId);
|
|
97
94
|
return source;
|
|
@@ -126,7 +123,7 @@ class ComputedNode extends Node {
|
|
|
126
123
|
}
|
|
127
124
|
}
|
|
128
125
|
checkDataAvailability() {
|
|
129
|
-
return Object.values(this.graph.resultsOf(this.
|
|
126
|
+
return Object.values(this.graph.resultsOf(this.inputs))
|
|
130
127
|
.flat()
|
|
131
128
|
.some((result) => result !== undefined);
|
|
132
129
|
}
|
|
@@ -195,7 +192,7 @@ class ComputedNode extends Node {
|
|
|
195
192
|
// then it removes itself from the "running node" list of the graph.
|
|
196
193
|
// Notice that setting the result of this node may make other nodes ready to run.
|
|
197
194
|
async execute() {
|
|
198
|
-
const previousResults = this.graph.resultsOf(this.
|
|
195
|
+
const previousResults = this.graph.resultsOf(this.inputs, this.anyInput);
|
|
199
196
|
const transactionId = Date.now();
|
|
200
197
|
this.prepareExecute(transactionId, Object.values(previousResults));
|
|
201
198
|
if (this.timeout && this.timeout > 0) {
|
|
@@ -206,22 +203,7 @@ class ComputedNode extends Node {
|
|
|
206
203
|
try {
|
|
207
204
|
const agentFunction = this.agentFunction ?? this.graph.getAgentFunctionInfo(this.agentId).agent;
|
|
208
205
|
const localLog = [];
|
|
209
|
-
const
|
|
210
|
-
const result = this.graph.resultOf(this.dynamicParams[key]);
|
|
211
|
-
tmp[key] = result;
|
|
212
|
-
return tmp;
|
|
213
|
-
}, { ...this.params });
|
|
214
|
-
const context = {
|
|
215
|
-
params: params,
|
|
216
|
-
inputs: this.getInputs(previousResults),
|
|
217
|
-
namedInputs: this.getNamedInput(previousResults),
|
|
218
|
-
inputSchema: this.agentFunction ? undefined : this.graph.getAgentFunctionInfo(this.agentId)?.inputs,
|
|
219
|
-
debugInfo: this.getDebugInfo(),
|
|
220
|
-
filterParams: this.filterParams,
|
|
221
|
-
agentFilters: this.graph.agentFilters,
|
|
222
|
-
config: this.graph.config,
|
|
223
|
-
log: localLog,
|
|
224
|
-
};
|
|
206
|
+
const context = this.getContext(previousResults, localLog);
|
|
225
207
|
// NOTE: We use the existence of graph object in the agent-specific params to determine
|
|
226
208
|
// if this is a nested agent or not.
|
|
227
209
|
if (this.nestedGraph) {
|
|
@@ -248,23 +230,13 @@ class ComputedNode extends Node {
|
|
|
248
230
|
return;
|
|
249
231
|
}
|
|
250
232
|
this.state = type_1.NodeState.Completed;
|
|
251
|
-
this.result = (
|
|
252
|
-
if (result && this.passThrough) {
|
|
253
|
-
if ((0, utils_2.isObject)(result) && !Array.isArray(result)) {
|
|
254
|
-
return { ...result, ...this.passThrough };
|
|
255
|
-
}
|
|
256
|
-
else if (Array.isArray(result)) {
|
|
257
|
-
return result.map((r) => ((0, utils_2.isObject)(r) && !Array.isArray(r) ? { ...r, ...this.passThrough } : r));
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return result;
|
|
261
|
-
})();
|
|
233
|
+
this.result = this.getResult(result);
|
|
262
234
|
this.log.onComplete(this, this.graph, localLog);
|
|
263
235
|
this.onSetResult();
|
|
264
236
|
this.graph.onExecutionComplete(this);
|
|
265
237
|
}
|
|
266
238
|
catch (error) {
|
|
267
|
-
this.errorProcess(error, transactionId);
|
|
239
|
+
this.errorProcess(error, transactionId, previousResults);
|
|
268
240
|
}
|
|
269
241
|
}
|
|
270
242
|
// This private method (called only by execute()) prepares the ComputedNode object
|
|
@@ -277,9 +249,10 @@ class ComputedNode extends Node {
|
|
|
277
249
|
// This private method (called only by execute) processes an error received from
|
|
278
250
|
// the agent function. It records the error in the transaction log and handles
|
|
279
251
|
// the retry if specified.
|
|
280
|
-
errorProcess(error, transactionId) {
|
|
252
|
+
errorProcess(error, transactionId, namedInputs) {
|
|
281
253
|
if (error instanceof Error && error.message !== utils_1.strIntentionalError) {
|
|
282
254
|
console.error(`<-- NodeId: ${this.nodeId}, Agent: ${this.agentId}`);
|
|
255
|
+
console.error({ namedInputs });
|
|
283
256
|
console.error(error);
|
|
284
257
|
console.error("-->");
|
|
285
258
|
}
|
|
@@ -295,22 +268,43 @@ class ComputedNode extends Node {
|
|
|
295
268
|
this.retry(type_1.NodeState.Failed, Error("Unknown"));
|
|
296
269
|
}
|
|
297
270
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return tmp;
|
|
305
|
-
}, {});
|
|
306
|
-
}
|
|
307
|
-
return {};
|
|
271
|
+
getParams() {
|
|
272
|
+
return Object.keys(this.dynamicParams).reduce((tmp, key) => {
|
|
273
|
+
const result = this.graph.resultOf(this.dynamicParams[key]);
|
|
274
|
+
tmp[key] = result;
|
|
275
|
+
return tmp;
|
|
276
|
+
}, { ...this.params });
|
|
308
277
|
}
|
|
309
278
|
getInputs(previousResults) {
|
|
310
|
-
if (this.
|
|
311
|
-
return [];
|
|
279
|
+
if (Array.isArray(this.inputs)) {
|
|
280
|
+
return (this.inputs ?? []).map((key) => previousResults[String(key)]).filter((a) => !this.anyInput || a);
|
|
281
|
+
}
|
|
282
|
+
return [];
|
|
283
|
+
}
|
|
284
|
+
getContext(previousResults, localLog) {
|
|
285
|
+
const context = {
|
|
286
|
+
params: this.getParams(),
|
|
287
|
+
inputs: this.getInputs(previousResults),
|
|
288
|
+
namedInputs: this.isNamedInputs ? previousResults : {},
|
|
289
|
+
inputSchema: this.agentFunction ? undefined : this.graph.getAgentFunctionInfo(this.agentId)?.inputs,
|
|
290
|
+
debugInfo: this.getDebugInfo(),
|
|
291
|
+
filterParams: this.filterParams,
|
|
292
|
+
agentFilters: this.graph.agentFilters,
|
|
293
|
+
config: this.graph.config,
|
|
294
|
+
log: localLog,
|
|
295
|
+
};
|
|
296
|
+
return context;
|
|
297
|
+
}
|
|
298
|
+
getResult(result) {
|
|
299
|
+
if (result && this.passThrough) {
|
|
300
|
+
if ((0, utils_2.isObject)(result) && !Array.isArray(result)) {
|
|
301
|
+
return { ...result, ...this.passThrough };
|
|
302
|
+
}
|
|
303
|
+
else if (Array.isArray(result)) {
|
|
304
|
+
return result.map((r) => ((0, utils_2.isObject)(r) && !Array.isArray(r) ? { ...r, ...this.passThrough } : r));
|
|
305
|
+
}
|
|
312
306
|
}
|
|
313
|
-
return
|
|
307
|
+
return result;
|
|
314
308
|
}
|
|
315
309
|
getDebugInfo() {
|
|
316
310
|
return {
|
|
@@ -324,7 +318,7 @@ class ComputedNode extends Node {
|
|
|
324
318
|
}
|
|
325
319
|
beforeConsoleLog(context) {
|
|
326
320
|
if (this.console.before === true) {
|
|
327
|
-
console.log(JSON.stringify(this.
|
|
321
|
+
console.log(JSON.stringify(this.isNamedInputs ? context.namedInputs : context.inputs, null, 2));
|
|
328
322
|
}
|
|
329
323
|
else if (this.console.before) {
|
|
330
324
|
console.log(this.console.before);
|
|
@@ -346,7 +340,7 @@ class StaticNode extends Node {
|
|
|
346
340
|
this.isStaticNode = true;
|
|
347
341
|
this.isComputedNode = false;
|
|
348
342
|
this.value = data.value;
|
|
349
|
-
this.update = data.update ? (0, utils_2.parseNodeName)(data.update
|
|
343
|
+
this.update = data.update ? (0, utils_2.parseNodeName)(data.update) : undefined;
|
|
350
344
|
this.isResult = data.isResult ?? false;
|
|
351
345
|
}
|
|
352
346
|
injectValue(value, injectFrom) {
|
package/lib/result.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DataSource, ResultData } from "./type";
|
|
2
|
+
import { GraphNodes } from "./node";
|
|
3
|
+
export declare const resultsOf: (inputs: Record<string, any> | Array<string>, nodes: GraphNodes) => Record<string, ResultData>;
|
|
4
|
+
export declare const resultOf: (source: DataSource, nodes: GraphNodes) => ResultData;
|
|
5
|
+
export declare const cleanResultInner: (results: ResultData) => ResultData | null;
|
|
6
|
+
export declare const cleanResult: (results: Record<string, ResultData | undefined>) => Record<string, ResultData>;
|
package/lib/result.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cleanResult = exports.cleanResultInner = exports.resultOf = exports.resultsOf = void 0;
|
|
4
|
+
const utils_1 = require("./utils/utils");
|
|
5
|
+
const resultsOfInner = (input, nodes) => {
|
|
6
|
+
if (Array.isArray(input)) {
|
|
7
|
+
return input.map((inp) => resultsOfInner(inp, nodes));
|
|
8
|
+
}
|
|
9
|
+
if ((0, utils_1.isNamedInputs)(input)) {
|
|
10
|
+
return (0, exports.resultsOf)(input, nodes);
|
|
11
|
+
}
|
|
12
|
+
if (typeof input === "string") {
|
|
13
|
+
const templateMatch = [...input.matchAll(/\${(:[^}]+)}/g)].map((m) => m[1]);
|
|
14
|
+
if (templateMatch.length > 0) {
|
|
15
|
+
const results = resultsOfInner(templateMatch, nodes);
|
|
16
|
+
return Array.from(templateMatch.keys()).reduce((tmp, key) => {
|
|
17
|
+
return tmp.replaceAll("${" + templateMatch[key] + "}", results[key]);
|
|
18
|
+
}, input);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return (0, exports.resultOf)((0, utils_1.parseNodeName)(input), nodes);
|
|
22
|
+
};
|
|
23
|
+
const resultsOf = (inputs, nodes) => {
|
|
24
|
+
// for inputs. TODO remove if array input is not supported
|
|
25
|
+
if (Array.isArray(inputs)) {
|
|
26
|
+
return inputs.reduce((tmp, key) => {
|
|
27
|
+
tmp[key] = resultsOfInner(key, nodes);
|
|
28
|
+
return tmp;
|
|
29
|
+
}, {});
|
|
30
|
+
}
|
|
31
|
+
return Object.keys(inputs).reduce((tmp, key) => {
|
|
32
|
+
const input = inputs[key];
|
|
33
|
+
tmp[key] = (0, utils_1.isNamedInputs)(input) ? (0, exports.resultsOf)(input, nodes) : resultsOfInner(input, nodes);
|
|
34
|
+
return tmp;
|
|
35
|
+
}, {});
|
|
36
|
+
};
|
|
37
|
+
exports.resultsOf = resultsOf;
|
|
38
|
+
const resultOf = (source, nodes) => {
|
|
39
|
+
const { result } = source.nodeId ? nodes[source.nodeId] : { result: undefined };
|
|
40
|
+
return (0, utils_1.getDataFromSource)(result, source);
|
|
41
|
+
};
|
|
42
|
+
exports.resultOf = resultOf;
|
|
43
|
+
// clean up object for anyInput
|
|
44
|
+
const cleanResultInner = (results) => {
|
|
45
|
+
if (Array.isArray(results)) {
|
|
46
|
+
return results.map((result) => (0, exports.cleanResultInner)(result)).filter((result) => !(0, utils_1.isNull)(result));
|
|
47
|
+
}
|
|
48
|
+
if ((0, utils_1.isObject)(results)) {
|
|
49
|
+
return Object.keys(results).reduce((tmp, key) => {
|
|
50
|
+
const value = (0, exports.cleanResultInner)(results[key]);
|
|
51
|
+
if (!(0, utils_1.isNull)(value)) {
|
|
52
|
+
tmp[key] = value;
|
|
53
|
+
}
|
|
54
|
+
return tmp;
|
|
55
|
+
}, {});
|
|
56
|
+
}
|
|
57
|
+
return results;
|
|
58
|
+
};
|
|
59
|
+
exports.cleanResultInner = cleanResultInner;
|
|
60
|
+
const cleanResult = (results) => {
|
|
61
|
+
return Object.keys(results).reduce((tmp, key) => {
|
|
62
|
+
const value = (0, exports.cleanResultInner)(results[key]);
|
|
63
|
+
if (!(0, utils_1.isNull)(value)) {
|
|
64
|
+
tmp[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return tmp;
|
|
67
|
+
}, {});
|
|
68
|
+
};
|
|
69
|
+
exports.cleanResult = cleanResult;
|
package/lib/transaction_log.js
CHANGED
|
@@ -44,7 +44,7 @@ class TransactionLog {
|
|
|
44
44
|
this.state = node.state;
|
|
45
45
|
this.retryCount = node.retryCount > 0 ? node.retryCount : undefined;
|
|
46
46
|
this.startTime = transactionId;
|
|
47
|
-
this.inputs = (0, nodeUtils_1.
|
|
47
|
+
this.inputs = (0, nodeUtils_1.dataSourceNodeIds)(node.dataSources);
|
|
48
48
|
this.inputsData = inputs.length > 0 ? inputs : undefined;
|
|
49
49
|
graph.setLoopLog(this);
|
|
50
50
|
graph.appendLog(this);
|
package/lib/type.d.ts
CHANGED
|
@@ -23,9 +23,6 @@ export type DataSource = {
|
|
|
23
23
|
value?: any;
|
|
24
24
|
propIds?: string[];
|
|
25
25
|
};
|
|
26
|
-
export type DataSources = DataSource | DataSource[] | DataSources[];
|
|
27
|
-
export type NestedDataSource = Record<string, DataSources>;
|
|
28
|
-
export type ResultDataSet = ResultData | ResultData[] | ResultDataSet[];
|
|
29
26
|
export type StaticNodeData = {
|
|
30
27
|
value: ResultData;
|
|
31
28
|
update?: string;
|
|
@@ -61,6 +58,7 @@ export type GraphData = {
|
|
|
61
58
|
loop?: LoopData;
|
|
62
59
|
verbose?: boolean;
|
|
63
60
|
retry?: number;
|
|
61
|
+
metadata?: any;
|
|
64
62
|
};
|
|
65
63
|
export type GraphOptions = {
|
|
66
64
|
agentFilters?: AgentFilterInfo[] | undefined;
|
|
@@ -118,6 +116,7 @@ export type AgentFunctionInfo = {
|
|
|
118
116
|
author: string;
|
|
119
117
|
repository: string;
|
|
120
118
|
license: string;
|
|
119
|
+
environmentVariables?: string[];
|
|
121
120
|
stream?: boolean;
|
|
122
121
|
apiKeys?: string[];
|
|
123
122
|
npms?: string[];
|
package/lib/utils/nodeUtils.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { DataSource
|
|
2
|
-
export declare const inputs2dataSources: (inputs:
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const flatDataSourceNodeIds: (sources: DataSource[] | DataSources[]) => string[];
|
|
5
|
-
export declare const flatDataSource: (sources: DataSource[] | DataSources[]) => DataSource[];
|
|
1
|
+
import { DataSource } from "../type";
|
|
2
|
+
export declare const inputs2dataSources: (inputs: any) => DataSource[];
|
|
3
|
+
export declare const dataSourceNodeIds: (sources: DataSource[]) => string[];
|
package/lib/utils/nodeUtils.js
CHANGED
|
@@ -1,49 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.dataSourceNodeIds = exports.inputs2dataSources = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return
|
|
9
|
-
}, {});
|
|
10
|
-
};
|
|
11
|
-
exports.inputs2dataSources = inputs2dataSources;
|
|
12
|
-
const nestedParseNodeName = (input, graphVersion) => {
|
|
13
|
-
if (Array.isArray(input)) {
|
|
14
|
-
return input.map((inp) => nestedParseNodeName(inp, graphVersion));
|
|
5
|
+
// for dataSource
|
|
6
|
+
const inputs2dataSources = (inputs) => {
|
|
7
|
+
if (Array.isArray(inputs)) {
|
|
8
|
+
return inputs.map((inp) => (0, exports.inputs2dataSources)(inp)).flat();
|
|
15
9
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
exports.namedInputs2dataSources = namedInputs2dataSources;
|
|
26
|
-
const flatDataSourceNodeIds = (sources) => {
|
|
27
|
-
return (0, exports.flatDataSource)(sources)
|
|
28
|
-
.filter((source) => source.nodeId)
|
|
29
|
-
.map((source) => source.nodeId);
|
|
30
|
-
};
|
|
31
|
-
exports.flatDataSourceNodeIds = flatDataSourceNodeIds;
|
|
32
|
-
const flatDataSource = (sources) => {
|
|
33
|
-
return sources
|
|
34
|
-
.map((source) => {
|
|
35
|
-
if (Array.isArray(source)) {
|
|
36
|
-
return source
|
|
37
|
-
.map((s) => {
|
|
38
|
-
if (Array.isArray(s)) {
|
|
39
|
-
return (0, exports.flatDataSource)(s);
|
|
40
|
-
}
|
|
41
|
-
return s;
|
|
42
|
-
})
|
|
43
|
-
.flat();
|
|
10
|
+
if ((0, utils_1.isObject)(inputs)) {
|
|
11
|
+
return Object.values(inputs)
|
|
12
|
+
.map((input) => (0, exports.inputs2dataSources)(input))
|
|
13
|
+
.flat();
|
|
14
|
+
}
|
|
15
|
+
if (typeof inputs === "string") {
|
|
16
|
+
const templateMatch = [...inputs.matchAll(/\${(:[^}]+)}/g)].map((m) => m[1]);
|
|
17
|
+
if (templateMatch.length > 0) {
|
|
18
|
+
return (0, exports.inputs2dataSources)(templateMatch);
|
|
44
19
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
20
|
+
}
|
|
21
|
+
return (0, utils_1.parseNodeName)(inputs);
|
|
22
|
+
};
|
|
23
|
+
exports.inputs2dataSources = inputs2dataSources;
|
|
24
|
+
const dataSourceNodeIds = (sources) => {
|
|
25
|
+
return sources.filter((source) => source.nodeId).map((source) => source.nodeId);
|
|
48
26
|
};
|
|
49
|
-
exports.
|
|
27
|
+
exports.dataSourceNodeIds = dataSourceNodeIds;
|
package/lib/utils/utils.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { DataSource, ResultData, AgentFunction } from "../type";
|
|
1
|
+
import { DataSource, ResultData, AgentFunction, DefaultInputData } from "../type";
|
|
2
2
|
export declare const sleep: (milliseconds: number) => Promise<unknown>;
|
|
3
|
-
export declare const parseNodeName: (inputNodeId: any
|
|
3
|
+
export declare const parseNodeName: (inputNodeId: any) => DataSource;
|
|
4
4
|
export declare function assert(condition: boolean, message: string, isWarn?: boolean): asserts condition;
|
|
5
5
|
export declare const isObject: (x: unknown) => x is object;
|
|
6
|
+
export declare const isNull: (data: unknown) => data is null | undefined;
|
|
6
7
|
export declare const getDataFromSource: (result: ResultData | undefined, source: DataSource) => ResultData | undefined;
|
|
7
8
|
export declare const strIntentionalError = "Intentional Error for Debugging";
|
|
8
9
|
export declare const defaultAgentInfo: {
|
|
@@ -46,3 +47,4 @@ export declare const defaultTestContext: {
|
|
|
46
47
|
agents: {};
|
|
47
48
|
log: never[];
|
|
48
49
|
};
|
|
50
|
+
export declare const isNamedInputs: <NamedInput = DefaultInputData>(namedInputs: NamedInput) => boolean;
|
package/lib/utils/utils.js
CHANGED
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultTestContext = exports.isLogicallyTrue = exports.debugResultKey = exports.agentInfoWrapper = exports.defaultAgentInfo = exports.strIntentionalError = exports.getDataFromSource = exports.isObject = exports.parseNodeName = exports.sleep = void 0;
|
|
3
|
+
exports.isNamedInputs = exports.defaultTestContext = exports.isLogicallyTrue = exports.debugResultKey = exports.agentInfoWrapper = exports.defaultAgentInfo = exports.strIntentionalError = exports.getDataFromSource = exports.isNull = exports.isObject = exports.parseNodeName = exports.sleep = void 0;
|
|
4
4
|
exports.assert = assert;
|
|
5
5
|
const sleep = async (milliseconds) => {
|
|
6
6
|
return await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
7
7
|
};
|
|
8
8
|
exports.sleep = sleep;
|
|
9
|
-
const
|
|
10
|
-
if (typeof inputNodeId === "string") {
|
|
11
|
-
const regex = /^"(.*)"$/;
|
|
12
|
-
const match = inputNodeId.match(regex);
|
|
13
|
-
if (match) {
|
|
14
|
-
return { value: match[1] }; // string literal
|
|
15
|
-
}
|
|
16
|
-
const parts = inputNodeId.split(".");
|
|
17
|
-
if (parts.length == 1) {
|
|
18
|
-
return { nodeId: parts[0] };
|
|
19
|
-
}
|
|
20
|
-
return { nodeId: parts[0], propIds: parts.slice(1) };
|
|
21
|
-
}
|
|
22
|
-
return { value: inputNodeId }; // non-string literal
|
|
23
|
-
};
|
|
24
|
-
const parseNodeName = (inputNodeId, version) => {
|
|
25
|
-
if (version === 0.2) {
|
|
26
|
-
return parseNodeName_02(inputNodeId);
|
|
27
|
-
}
|
|
9
|
+
const parseNodeName = (inputNodeId) => {
|
|
28
10
|
if (typeof inputNodeId === "string") {
|
|
29
11
|
const regex = /^:(.*)$/;
|
|
30
12
|
const match = inputNodeId.match(regex);
|
|
@@ -52,8 +34,14 @@ const isObject = (x) => {
|
|
|
52
34
|
return x !== null && typeof x === "object";
|
|
53
35
|
};
|
|
54
36
|
exports.isObject = isObject;
|
|
37
|
+
const isNull = (data) => {
|
|
38
|
+
return data === null || data === undefined;
|
|
39
|
+
};
|
|
40
|
+
exports.isNull = isNull;
|
|
55
41
|
const getNestedData = (result, propId) => {
|
|
42
|
+
// for array.
|
|
56
43
|
if (Array.isArray(result)) {
|
|
44
|
+
// $0, $1. array value.
|
|
57
45
|
const regex = /^\$(\d+)$/;
|
|
58
46
|
const match = propId.match(regex);
|
|
59
47
|
if (match) {
|
|
@@ -63,9 +51,51 @@ const getNestedData = (result, propId) => {
|
|
|
63
51
|
if (propId === "$last") {
|
|
64
52
|
return result[result.length - 1];
|
|
65
53
|
}
|
|
54
|
+
if (propId === "length()") {
|
|
55
|
+
return result.length;
|
|
56
|
+
}
|
|
57
|
+
if (propId === "flat()") {
|
|
58
|
+
return result.flat();
|
|
59
|
+
}
|
|
60
|
+
if (propId === "toJSON()") {
|
|
61
|
+
return JSON.stringify(result);
|
|
62
|
+
}
|
|
63
|
+
// array join
|
|
64
|
+
const matchJoin = propId.match(/^join\(([,-]?)\)$/);
|
|
65
|
+
if (matchJoin && Array.isArray(matchJoin)) {
|
|
66
|
+
return result.join(matchJoin[1] ?? "");
|
|
67
|
+
}
|
|
68
|
+
// flat, join
|
|
66
69
|
}
|
|
67
70
|
else if ((0, exports.isObject)(result)) {
|
|
68
|
-
|
|
71
|
+
if (propId === "keys()") {
|
|
72
|
+
return Object.keys(result);
|
|
73
|
+
}
|
|
74
|
+
if (propId === "values()") {
|
|
75
|
+
return Object.values(result);
|
|
76
|
+
}
|
|
77
|
+
if (propId === "toJSON()") {
|
|
78
|
+
return JSON.stringify(result);
|
|
79
|
+
}
|
|
80
|
+
if (propId in result) {
|
|
81
|
+
return result[propId];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (typeof result === "string") {
|
|
85
|
+
if (propId === "jsonParse()") {
|
|
86
|
+
return JSON.parse(result);
|
|
87
|
+
}
|
|
88
|
+
if (propId === "toNumber()") {
|
|
89
|
+
const ret = Number(result);
|
|
90
|
+
if (!isNaN(ret)) {
|
|
91
|
+
return ret;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (Number.isFinite(result)) {
|
|
96
|
+
if (propId === "toString()") {
|
|
97
|
+
return String(result);
|
|
98
|
+
}
|
|
69
99
|
}
|
|
70
100
|
return undefined;
|
|
71
101
|
};
|
|
@@ -73,6 +103,9 @@ const innerGetDataFromSource = (result, propIds) => {
|
|
|
73
103
|
if (result && propIds && propIds.length > 0) {
|
|
74
104
|
const propId = propIds[0];
|
|
75
105
|
const ret = getNestedData(result, propId);
|
|
106
|
+
if (ret === undefined) {
|
|
107
|
+
console.error(`prop: ${propIds.join(".")} is not hit`);
|
|
108
|
+
}
|
|
76
109
|
if (propIds.length > 1) {
|
|
77
110
|
return innerGetDataFromSource(ret, propIds.slice(1));
|
|
78
111
|
}
|
|
@@ -166,3 +199,7 @@ exports.defaultTestContext = {
|
|
|
166
199
|
agents: {},
|
|
167
200
|
log: [],
|
|
168
201
|
};
|
|
202
|
+
const isNamedInputs = (namedInputs) => {
|
|
203
|
+
return (0, exports.isObject)(namedInputs) && !Array.isArray(namedInputs) && Object.keys(namedInputs || {}).length > 0;
|
|
204
|
+
};
|
|
205
|
+
exports.isNamedInputs = isNamedInputs;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.relationValidator = void 0;
|
|
4
4
|
const utils_1 = require("../utils/utils");
|
|
5
5
|
const common_1 = require("../validators/common");
|
|
6
|
+
const nodeUtils_1 = require("../utils/nodeUtils");
|
|
6
7
|
const relationValidator = (data, staticNodeIds, computedNodeIds) => {
|
|
7
8
|
const nodeIds = new Set(Object.keys(data.nodes));
|
|
8
9
|
const pendings = {};
|
|
@@ -11,34 +12,34 @@ const relationValidator = (data, staticNodeIds, computedNodeIds) => {
|
|
|
11
12
|
computedNodeIds.forEach((computedNodeId) => {
|
|
12
13
|
const nodeData = data.nodes[computedNodeId];
|
|
13
14
|
pendings[computedNodeId] = new Set();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!nodeIds.has(sourceNodeId)) {
|
|
20
|
-
throw new common_1.ValidationError(`Inputs not match: NodeId ${computedNodeId}, Inputs: ${sourceNodeId}`);
|
|
21
|
-
}
|
|
22
|
-
waitlist[sourceNodeId] === undefined && (waitlist[sourceNodeId] = new Set());
|
|
23
|
-
pendings[computedNodeId].add(sourceNodeId);
|
|
24
|
-
waitlist[sourceNodeId].add(computedNodeId);
|
|
15
|
+
const dataSourceValidator = (sourceType, sourceNodeIds) => {
|
|
16
|
+
sourceNodeIds.forEach((sourceNodeId) => {
|
|
17
|
+
if (sourceNodeId) {
|
|
18
|
+
if (!nodeIds.has(sourceNodeId)) {
|
|
19
|
+
throw new common_1.ValidationError(`${sourceType} not match: NodeId ${computedNodeId}, Inputs: ${sourceNodeId}`);
|
|
25
20
|
}
|
|
26
|
-
|
|
21
|
+
waitlist[sourceNodeId] === undefined && (waitlist[sourceNodeId] = new Set());
|
|
22
|
+
pendings[computedNodeId].add(sourceNodeId);
|
|
23
|
+
waitlist[sourceNodeId].add(computedNodeId);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
if ("agent" in nodeData && nodeData) {
|
|
28
|
+
if (nodeData.inputs) {
|
|
29
|
+
const sourceNodeIds = (0, nodeUtils_1.dataSourceNodeIds)((0, nodeUtils_1.inputs2dataSources)(nodeData.inputs));
|
|
30
|
+
dataSourceValidator("Inputs", sourceNodeIds);
|
|
27
31
|
}
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
waitlist[sourceNodeId].add(computedNodeId);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
32
|
+
if (nodeData.if) {
|
|
33
|
+
const sourceNodeIds = (0, nodeUtils_1.dataSourceNodeIds)((0, nodeUtils_1.inputs2dataSources)({ if: nodeData.if }));
|
|
34
|
+
dataSourceValidator("If", sourceNodeIds);
|
|
35
|
+
}
|
|
36
|
+
if (nodeData.unless) {
|
|
37
|
+
const sourceNodeIds = (0, nodeUtils_1.dataSourceNodeIds)((0, nodeUtils_1.inputs2dataSources)({ unless: nodeData.unless }));
|
|
38
|
+
dataSourceValidator("Unless", sourceNodeIds);
|
|
39
|
+
}
|
|
40
|
+
if (nodeData.graph && typeof nodeData?.graph === "string") {
|
|
41
|
+
const sourceNodeIds = (0, nodeUtils_1.dataSourceNodeIds)((0, nodeUtils_1.inputs2dataSources)({ graph: nodeData.graph }));
|
|
42
|
+
dataSourceValidator("Graph", sourceNodeIds);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
});
|
|
@@ -47,7 +48,7 @@ const relationValidator = (data, staticNodeIds, computedNodeIds) => {
|
|
|
47
48
|
const nodeData = data.nodes[staticNodeId];
|
|
48
49
|
if ("value" in nodeData && nodeData.update) {
|
|
49
50
|
const update = nodeData.update;
|
|
50
|
-
const updateNodeId = (0, utils_1.parseNodeName)(update
|
|
51
|
+
const updateNodeId = (0, utils_1.parseNodeName)(update).nodeId;
|
|
51
52
|
if (!updateNodeId) {
|
|
52
53
|
throw new common_1.ValidationError("Update it a literal");
|
|
53
54
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphai",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "Asynchronous data flow execution engine for agentic AI apps.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/receptron/graphai#readme",
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"typedoc": "^0.26.
|
|
29
|
+
"typedoc": "^0.26.10"
|
|
30
30
|
},
|
|
31
31
|
"types": "./lib/index.d.ts",
|
|
32
32
|
"directories": {
|