graphai 0.0.5 → 0.0.7

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.
@@ -0,0 +1,21 @@
1
+ import path from "path";
2
+ import { AgentFunction } from "@/graphai";
3
+ import { ChatSession, ChatConfig, ManifestData } from "slashgpt";
4
+
5
+ const config = new ChatConfig(path.resolve(__dirname));
6
+
7
+ export const slashGPTAgent: AgentFunction<{ manifest: ManifestData; prompt: string }, { answer: string }> = async (context) => {
8
+ console.log("executing", context.nodeId, context);
9
+ const session = new ChatSession(config, context.params?.manifest ?? {});
10
+
11
+ const prompt = [context.params?.prompt, context.payload.inputData].join("\n\n");
12
+ session.append_user_question(prompt);
13
+
14
+ await session.call_loop(() => {});
15
+ const message = session.history.last_message();
16
+ if (message === undefined) {
17
+ throw new Error("No message in the history");
18
+ }
19
+ const result = { answer: message.content };
20
+ return result;
21
+ };
@@ -0,0 +1,47 @@
1
+ // npx ts-node samples/express.ts
2
+ import { GraphAI, AgentFunction } from "@/graphai";
3
+
4
+ import express from "express";
5
+
6
+ const app = express();
7
+
8
+ const graphAISample = async (req: express.Request, res: express.Response) => {
9
+ const graph_data = {
10
+ nodes: {
11
+ node1: {
12
+ params: {},
13
+ },
14
+ },
15
+ concurrency: 8,
16
+ };
17
+ const testFunction: AgentFunction<Record<string, string>> = async (context) => {
18
+ console.log("hello");
19
+ return {};
20
+ };
21
+ const graph = new GraphAI(graph_data, testFunction);
22
+ const response = await graph.run();
23
+ res.json({ result: response });
24
+ res.end();
25
+ };
26
+
27
+ const hello = async (req: express.Request, res: express.Response) => {
28
+ const { params, query } = req;
29
+ res.json({
30
+ result: [
31
+ {
32
+ message: "hello",
33
+ params,
34
+ query,
35
+ },
36
+ ],
37
+ });
38
+ res.end();
39
+ };
40
+
41
+ app.use(express.json());
42
+ app.get("/", hello);
43
+ app.get("/mock", graphAISample);
44
+
45
+ const server = app.listen(8080, () => {
46
+ console.log("Running Server");
47
+ });
@@ -0,0 +1,29 @@
1
+ nodes:
2
+ searchArxiv:
3
+ params:
4
+ keywords:
5
+ - llm
6
+ - gpt
7
+ limit: 10
8
+ functionName: arxivAgent
9
+ arxiv2TextAgent:
10
+ inputs: [searchArxiv]
11
+ functionName: arxiv2TextAgent
12
+ payloadMapping:
13
+ searchArxiv: inputData
14
+ slashGPTAgent:
15
+ inputs: [arxiv2TextAgent]
16
+ payloadMapping:
17
+ arxiv2TextAgent: inputData
18
+ functionName: slashGPTAgent
19
+ params:
20
+ prompt: |
21
+ 与えられたそれぞれの論文の要点をまとめ、以下の項目で日本語で出力せよ。それぞれの項目は最大でも180文字以内に要約せよ。
22
+ ```
23
+ 論文名:タイトルの日本語訳
24
+ キーワード:この論文のキーワード
25
+ 課題:この論文が解決する課題
26
+ 手法:この論文が提案する手法,
27
+ 結果:提案手法によって得られた結果
28
+ ```
29
+
@@ -1,11 +1,11 @@
1
1
  import path from "path";
2
- import { GraphAI, NodeExecute } from "../src/graphai";
3
- import { ChatSession, ChatConfig } from "slashgpt";
4
- import { readManifestData } from "../tests/file_utils";
2
+ import { GraphAI, AgentFunction } from "@/graphai";
3
+ import { ChatSession, ChatConfig, ManifestData } from "slashgpt";
4
+ import { readGraphaiData } from "~/utils/file_utils";
5
5
 
6
6
  const config = new ChatConfig(path.resolve(__dirname));
7
7
 
8
- const testFunction: NodeExecute<Record<string, string>> = async (context) => {
8
+ const slashGPTAgent: AgentFunction<{ manifest: ManifestData; prompt: string }, { answer: string }> = async (context) => {
9
9
  console.log("executing", context.nodeId, context.params);
10
10
  const session = new ChatSession(config, context.params.manifest ?? {});
11
11
  const prompt = Object.keys(context.payload).reduce((prompt, key) => {
@@ -19,19 +19,19 @@ const testFunction: NodeExecute<Record<string, string>> = async (context) => {
19
19
  throw new Error("No message in the history");
20
20
  }
21
21
  const result = { answer: message.content };
22
- console.log(result);
23
22
  return result;
24
23
  };
25
24
 
26
- const test = async (file: string) => {
25
+ const runAgent = async (file: string) => {
27
26
  const file_path = path.resolve(__dirname) + file;
28
- const graph_data = readManifestData(file_path);
29
- const graph = new GraphAI(graph_data, testFunction);
30
- await graph.run();
27
+ const graph_data = readGraphaiData(file_path);
28
+ const graph = new GraphAI(graph_data, slashGPTAgent);
29
+ const result = await graph.run();
30
+ console.log(result);
31
31
  };
32
32
 
33
33
  const main = async () => {
34
- await test("/graphs/slash_gpt.yml");
34
+ await runAgent("/graphs/slash_gpt.yml");
35
35
  console.log("COMPLETE 1");
36
36
  };
37
37
  main();
@@ -0,0 +1,26 @@
1
+ import path from "path";
2
+ import search from "arXiv-api-ts";
3
+
4
+ import { GraphAI, AgentFunction } from "@/graphai";
5
+ import { readGraphaiData } from "~/utils/file_utils";
6
+
7
+ import { slashGPTAgent } from "./agents/slashgpt_agent";
8
+ import { arxivAgent, arxiv2TextAgent } from "./agents/arxiv_agent";
9
+
10
+ export const parrotingAgent: AgentFunction = async (context) => {
11
+ return {};
12
+ };
13
+
14
+ const runAgent = async (file: string) => {
15
+ const file_path = path.resolve(__dirname) + file;
16
+ const graph_data = readGraphaiData(file_path);
17
+ const graph = new GraphAI(graph_data, { default: parrotingAgent, arxivAgent: arxivAgent, arxiv2TextAgent, slashGPTAgent });
18
+ const result = await graph.run();
19
+ console.log(result);
20
+ };
21
+
22
+ const main = async () => {
23
+ await runAgent("/graphs/arxiv.yml");
24
+ console.log("COMPLETE 1");
25
+ };
26
+ main();
package/src/graphai.ts CHANGED
@@ -1,81 +1,90 @@
1
- import { AssertionError } from "assert";
2
-
3
1
  export enum NodeState {
4
- Waiting,
5
- Executing,
6
- Failed,
7
- TimedOut,
8
- Completed,
2
+ Waiting = "waiting",
3
+ Executing = "executing",
4
+ Failed = "failed",
5
+ TimedOut = "timed-out",
6
+ Completed = "completed",
7
+ Injected = "injected",
8
+ Dispatched = "dispatched",
9
9
  }
10
10
  type ResultData<ResultType = Record<string, any>> = ResultType | undefined;
11
11
  type ResultDataDictonary<ResultType = Record<string, any>> = Record<string, ResultData<ResultType>>;
12
12
 
13
- export type NodeDataParams<ParamsType = Record<string, any>> = ParamsType; // App-specific parameters
13
+ export type NodeDataParams<ParamsType = Record<string, any>> = ParamsType; // Agent-specific parameters
14
14
 
15
15
  type NodeData = {
16
- inputs: undefined | Array<string>;
16
+ inputs?: Array<string>;
17
17
  params: NodeDataParams;
18
- retry: undefined | number;
19
- timeout: undefined | number; // msec
20
- functionName: undefined | string;
18
+ payloadMapping?: Record<string, string>;
19
+ retry?: number;
20
+ timeout?: number; // msec
21
+ agentId?: string;
22
+ source?: boolean;
23
+ dispatch?: Record<string, string>; // route to node
21
24
  };
22
25
 
23
- type GraphData = {
26
+ export type GraphData = {
24
27
  nodes: Record<string, NodeData>;
25
- concurrency: number;
26
- };
27
-
28
- type NodeExecuteContext<ResultType, ParamsType> = {
29
- nodeId: string;
30
- retry: number;
31
- params: NodeDataParams<ParamsType>;
32
- payload: ResultDataDictonary<ResultType>;
28
+ concurrency?: number;
33
29
  };
34
30
 
35
31
  export type TransactionLog = {
36
32
  nodeId: string;
37
33
  state: NodeState;
38
- startTime: undefined | number;
39
- endTime: undefined | number;
34
+ startTime: number;
35
+ endTime?: number;
40
36
  retryCount: number;
41
- error: undefined | Error;
37
+ agentId?: string;
38
+ params?: NodeDataParams;
39
+ payload?: ResultDataDictonary<ResultData>;
40
+ errorMessage?: string;
42
41
  result?: ResultData;
43
42
  };
44
43
 
45
- export type NodeExecute<ResultType = Record<string, any>, ParamsType = Record<string, any>> = (
46
- context: NodeExecuteContext<ResultType, ParamsType>,
44
+ export type AgentFunctionContext<ParamsType, ResultType, PreviousResultType> = {
45
+ nodeId: string;
46
+ retry: number;
47
+ params: NodeDataParams<ParamsType>;
48
+ payload: ResultDataDictonary<PreviousResultType>;
49
+ };
50
+
51
+ export type AgentFunction<ParamsType = Record<string, any>, ResultType = Record<string, any>, PreviousResultType = Record<string, any>> = (
52
+ context: AgentFunctionContext<ParamsType, ResultType, PreviousResultType>,
47
53
  ) => Promise<ResultData<ResultType>>;
48
54
 
55
+ export type AgentFunctionDictonary = Record<string, AgentFunction<any, any, any>>;
56
+
49
57
  class Node {
50
58
  public nodeId: string;
51
- public params: NodeDataParams; // App-specific parameters
59
+ public params: NodeDataParams; // Agent-specific parameters
52
60
  public inputs: Array<string>; // List of nodes this node needs data from.
61
+ public payloadMapping: Record<string, string>;
53
62
  public pendings: Set<string>; // List of nodes this node is waiting data from.
54
- public waitlist: Set<string>; // List of nodes which need data from this node.
55
- public state: NodeState;
56
- public functionName: string;
57
- public result: ResultData;
63
+ public waitlist = new Set<string>(); // List of nodes which need data from this node.
64
+ public state = NodeState.Waiting;
65
+ public agentId: string;
66
+ public result: ResultData = undefined;
58
67
  public retryLimit: number;
59
- public retryCount: number;
68
+ public retryCount: number = 0;
60
69
  public transactionId: undefined | number; // To reject callbacks from timed-out transactions
61
- public timeout: number; // msec
62
- public error: undefined | Error;
70
+ public timeout?: number; // msec
71
+ public error?: Error;
72
+ public source: boolean;
73
+ public dispatch?: Record<string, string>; // outputId to nodeId mapping
63
74
 
64
75
  private graph: GraphAI;
65
76
 
66
77
  constructor(nodeId: string, data: NodeData, graph: GraphAI) {
67
78
  this.nodeId = nodeId;
68
79
  this.inputs = data.inputs ?? [];
80
+ this.payloadMapping = data.payloadMapping ?? {};
69
81
  this.pendings = new Set(this.inputs);
70
82
  this.params = data.params;
71
- this.waitlist = new Set<string>();
72
- this.state = NodeState.Waiting;
73
- this.functionName = data.functionName ?? "default";
74
- this.result = undefined;
83
+ this.agentId = data.agentId ?? "default";
75
84
  this.retryLimit = data.retry ?? 0;
76
- this.retryCount = 0;
77
- this.timeout = data.timeout ?? 0;
78
-
85
+ this.timeout = data.timeout;
86
+ this.source = data.source === true;
87
+ this.dispatch = data.dispatch;
79
88
  this.graph = graph;
80
89
  }
81
90
 
@@ -91,48 +100,82 @@ class Node {
91
100
  this.state = state;
92
101
  this.result = undefined;
93
102
  this.error = error;
94
- this.transactionId = 0; // This is necessary for timeout case
103
+ this.transactionId = undefined; // This is necessary for timeout case
95
104
  this.graph.removeRunning(this);
96
105
  }
97
106
  }
98
107
 
99
108
  public removePending(nodeId: string) {
100
109
  this.pendings.delete(nodeId);
101
- this.pushQueueIfReady();
110
+ if (this.graph.isRunning) {
111
+ this.pushQueueIfReady();
112
+ }
102
113
  }
103
114
 
104
115
  public payload() {
105
116
  return this.inputs.reduce((results: ResultDataDictonary, nodeId) => {
106
- results[nodeId] = this.graph.nodes[nodeId].result;
117
+ if (this.payloadMapping && this.payloadMapping[nodeId]) {
118
+ results[this.payloadMapping[nodeId]] = this.graph.nodes[nodeId].result;
119
+ } else {
120
+ results[nodeId] = this.graph.nodes[nodeId].result;
121
+ }
107
122
  return results;
108
123
  }, {});
109
124
  }
110
125
 
111
126
  public pushQueueIfReady() {
112
- if (this.pendings.size === 0) {
127
+ if (this.pendings.size === 0 && !this.source) {
113
128
  this.graph.pushQueue(this);
114
129
  }
115
130
  }
116
131
 
132
+ public injectResult(result: ResultData) {
133
+ if (this.source) {
134
+ const log: TransactionLog = {
135
+ nodeId: this.nodeId,
136
+ retryCount: this.retryCount,
137
+ state: NodeState.Injected,
138
+ startTime: Date.now(),
139
+ };
140
+ log.endTime = log.startTime;
141
+ this.graph.appendLog(log);
142
+ this.setResult(result, NodeState.Injected);
143
+ } else {
144
+ console.error("- injectResult called on non-source node.", this.nodeId);
145
+ }
146
+ }
147
+
148
+ private setResult(result: ResultData, state: NodeState) {
149
+ this.state = state;
150
+ this.result = result;
151
+ this.waitlist.forEach((nodeId) => {
152
+ const node = this.graph.nodes[nodeId];
153
+ // Todo: Avoid running before Run()
154
+ node.removePending(this.nodeId);
155
+ });
156
+ }
157
+
117
158
  public async execute() {
159
+ const payload = this.payload();
118
160
  const log: TransactionLog = {
119
161
  nodeId: this.nodeId,
120
162
  retryCount: this.retryCount,
121
163
  state: NodeState.Executing,
122
164
  startTime: Date.now(),
123
- endTime: undefined,
124
- error: undefined,
165
+ agentId: this.agentId,
166
+ params: this.params,
167
+ payload,
125
168
  };
126
169
  this.graph.appendLog(log);
127
170
  this.state = NodeState.Executing;
128
171
  const transactionId = log.startTime;
129
172
  this.transactionId = transactionId;
130
173
 
131
- if (this.timeout > 0) {
174
+ if (this.timeout && this.timeout > 0) {
132
175
  setTimeout(() => {
133
176
  if (this.state === NodeState.Executing && this.transactionId === transactionId) {
134
177
  console.log(`-- ${this.nodeId}: timeout ${this.timeout}`);
135
- log.error = Error("Timeout");
178
+ log.errorMessage = "Timeout";
136
179
  log.state = NodeState.TimedOut;
137
180
  log.endTime = Date.now();
138
181
  this.retry(NodeState.TimedOut, Error("Timeout"));
@@ -141,26 +184,34 @@ class Node {
141
184
  }
142
185
 
143
186
  try {
144
- const callback = this.graph.getCallback(this.functionName);
187
+ const callback = this.graph.getCallback(this.agentId);
145
188
  const result = await callback({
146
189
  nodeId: this.nodeId,
147
190
  retry: this.retryCount,
148
191
  params: this.params,
149
- payload: this.payload(),
192
+ payload,
150
193
  });
151
194
  if (this.transactionId !== transactionId) {
152
195
  console.log(`-- ${this.nodeId}: transactionId mismatch`);
153
196
  return;
154
197
  }
155
- log.state = NodeState.Completed;
198
+
156
199
  log.endTime = Date.now();
157
200
  log.result = result;
158
- this.state = NodeState.Completed;
159
- this.result = result;
160
- this.waitlist.forEach((nodeId) => {
161
- const node = this.graph.nodes[nodeId];
162
- node.removePending(this.nodeId);
163
- });
201
+
202
+ const dispatch = this.dispatch;
203
+ if (dispatch !== undefined) {
204
+ Object.keys(result).forEach((outputId) => {
205
+ const nodeId = dispatch[outputId];
206
+ this.graph.injectResult(nodeId, result[outputId]);
207
+ });
208
+ log.state = NodeState.Dispatched;
209
+ this.state = NodeState.Dispatched;
210
+ this.graph.removeRunning(this);
211
+ return;
212
+ }
213
+ log.state = NodeState.Completed;
214
+ this.setResult(result, NodeState.Completed);
164
215
  this.graph.removeRunning(this);
165
216
  } catch (error) {
166
217
  if (this.transactionId !== transactionId) {
@@ -170,11 +221,11 @@ class Node {
170
221
  log.state = NodeState.Failed;
171
222
  log.endTime = Date.now();
172
223
  if (error instanceof Error) {
173
- log.error = error;
224
+ log.errorMessage = error.message;
174
225
  this.retry(NodeState.Failed, error);
175
226
  } else {
176
227
  console.error(`-- ${this.nodeId}: Unexpecrted error was caught`);
177
- log.error = Error("Unknown");
228
+ log.errorMessage = "Unknown";
178
229
  this.retry(NodeState.Failed, Error("Unknown"));
179
230
  }
180
231
  }
@@ -183,28 +234,27 @@ class Node {
183
234
 
184
235
  type GraphNodes = Record<string, Node>;
185
236
 
186
- type NodeExecuteDictonary = Record<string, NodeExecute>;
187
-
188
237
  const defaultConcurrency = 8;
189
238
 
190
239
  export class GraphAI {
191
240
  public nodes: GraphNodes;
192
- public callbackDictonary: NodeExecuteDictonary;
193
- private runningNodes: Set<string>;
194
- private nodeQueue: Array<Node>;
241
+ public callbackDictonary: AgentFunctionDictonary;
242
+ public isRunning = false;
243
+ private runningNodes = new Set<string>();
244
+ private nodeQueue: Array<Node> = [];
195
245
  private onComplete: () => void;
196
246
  private concurrency: number;
197
247
  private logs: Array<TransactionLog> = [];
198
248
 
199
- constructor(data: GraphData, callbackDictonary: NodeExecuteDictonary | NodeExecute) {
249
+ constructor(data: GraphData, callbackDictonary: AgentFunctionDictonary | AgentFunction<any, any, any>) {
200
250
  this.callbackDictonary = typeof callbackDictonary === "function" ? { default: callbackDictonary } : callbackDictonary;
201
251
  if (this.callbackDictonary["default"] === undefined) {
202
252
  throw new Error("No default function");
203
253
  }
204
254
  this.concurrency = data.concurrency ?? defaultConcurrency;
205
- this.runningNodes = new Set<string>();
206
- this.nodeQueue = [];
207
- this.onComplete = () => {};
255
+ this.onComplete = () => {
256
+ console.error("-- SOMETHING IS WRONG: onComplete is called without run()");
257
+ };
208
258
  this.nodes = Object.keys(data.nodes).reduce((nodes: GraphNodes, nodeId: string) => {
209
259
  nodes[nodeId] = new Node(nodeId, data.nodes[nodeId], this);
210
260
  return nodes;
@@ -220,9 +270,9 @@ export class GraphAI {
220
270
  });
221
271
  }
222
272
 
223
- public getCallback(functionName: string) {
224
- if (functionName && this.callbackDictonary[functionName]) {
225
- return this.callbackDictonary[functionName];
273
+ public getCallback(agentId: string) {
274
+ if (agentId && this.callbackDictonary[agentId]) {
275
+ return this.callbackDictonary[agentId];
226
276
  }
227
277
  return this.callbackDictonary["default"];
228
278
  }
@@ -256,6 +306,10 @@ export class GraphAI {
256
306
  }
257
307
 
258
308
  public async run() {
309
+ if (this.isRunning) {
310
+ console.error("-- Already Running");
311
+ }
312
+ this.isRunning = true;
259
313
  // Nodes without pending data should run immediately.
260
314
  Object.keys(this.nodes).forEach((nodeId) => {
261
315
  const node = this.nodes[nodeId];
@@ -264,6 +318,7 @@ export class GraphAI {
264
318
 
265
319
  return new Promise((resolve, reject) => {
266
320
  this.onComplete = () => {
321
+ this.isRunning = false;
267
322
  const errors = this.errors();
268
323
  const nodeIds = Object.keys(errors);
269
324
  if (nodeIds.length > 0) {
@@ -308,4 +363,13 @@ export class GraphAI {
308
363
  public transactionLogs() {
309
364
  return this.logs;
310
365
  }
366
+
367
+ public injectResult(nodeId: string, result: ResultData) {
368
+ const node = this.nodes[nodeId];
369
+ if (node) {
370
+ node.injectResult(result);
371
+ } else {
372
+ console.error("-- Invalid nodeId", nodeId);
373
+ }
374
+ }
311
375
  }
@@ -0,0 +1,24 @@
1
+ import { AgentFunction } from "@/graphai";
2
+ import { sleep } from "~/utils/utils";
3
+
4
+ export const testAgent: AgentFunction<{ delay: number; fail: boolean }> = async (context) => {
5
+ const { nodeId, retry, params, payload } = context;
6
+ console.log("executing", nodeId);
7
+ await sleep(params.delay / (retry + 1));
8
+
9
+ if (params.fail && retry < 2) {
10
+ const result = { [nodeId]: "failed" };
11
+ console.log("failed (intentional)", nodeId, retry);
12
+ throw new Error("Intentional Failure");
13
+ } else {
14
+ const result = Object.keys(payload).reduce(
15
+ (result, key) => {
16
+ result = { ...result, ...payload[key] };
17
+ return result;
18
+ },
19
+ { [nodeId]: "output" },
20
+ );
21
+ console.log("completing", nodeId);
22
+ return result;
23
+ }
24
+ };
@@ -0,0 +1,42 @@
1
+ import { AgentFunction } from "@/graphai";
2
+ import { fileTestRunner } from "~/utils/runner";
3
+
4
+ import { sleep } from "~/utils/utils";
5
+
6
+ import { testAgent } from "~/agents/agents";
7
+
8
+ import test from "node:test";
9
+ import assert from "node:assert";
10
+
11
+ const dispatchAgent: AgentFunction<{ delay: number; fail: boolean }> = async (context) => {
12
+ const { nodeId, retry, params, payload } = context;
13
+ console.log("executing", nodeId);
14
+ await sleep(params.delay / (retry + 1));
15
+
16
+ if (params.fail && retry < 2) {
17
+ const result = { [nodeId]: "failed" };
18
+ console.log("failed (intentional)", nodeId, retry);
19
+ throw new Error("Intentional Failure");
20
+ } else {
21
+ const result = Object.keys(payload).reduce(
22
+ (result, key) => {
23
+ result = { ...result, ...payload[key] };
24
+ return result;
25
+ },
26
+ { [nodeId]: "dispatch" },
27
+ );
28
+ console.log("completing", nodeId);
29
+ return { output1: result };
30
+ }
31
+ };
32
+
33
+ test("test dispatch", async () => {
34
+ const result = await fileTestRunner("/graphs/test_dispatch.yml", { default: testAgent, alt: dispatchAgent });
35
+ assert.deepStrictEqual(result, {
36
+ node1: { node1: "output" },
37
+ node20: { node2: "dispatch" },
38
+ node3: { node3: "output", node1: "output", node2: "dispatch" },
39
+ node4: { node4: "output", node3: "output", node1: "output", node2: "dispatch" },
40
+ node5: { node5: "output", node4: "output", node3: "output", node1: "output", node2: "dispatch" },
41
+ });
42
+ });
@@ -0,0 +1,40 @@
1
+ import { GraphAI, AgentFunction } from "@/graphai";
2
+ import { graphDataTestRunner } from "~/utils/runner";
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert";
6
+
7
+ const httpClientAgent: AgentFunction<Record<string, string>> = async (context) => {
8
+ const { nodeId, retry, params, payload } = context;
9
+ console.log("executing", nodeId, params, payload);
10
+
11
+ const response = await fetch(params.url);
12
+ const result = await response.json();
13
+
14
+ console.log("completing", nodeId, result);
15
+ return result;
16
+ };
17
+
18
+ const graph_data = {
19
+ nodes: {
20
+ node1: {
21
+ params: {
22
+ url: "http://127.0.0.1:8080/llm.json",
23
+ },
24
+ },
25
+ node2: {
26
+ params: {
27
+ url: "http://127.0.0.1:8080/llm2.json",
28
+ },
29
+ inputs: ["node1"],
30
+ },
31
+ },
32
+ };
33
+
34
+ test("test sample1", async () => {
35
+ const result = await graphDataTestRunner("http.log", graph_data, httpClientAgent);
36
+ assert.deepStrictEqual(result, {
37
+ node1: { result: true, messages: ["hello"] },
38
+ node2: { result: true, messages: ["hello2"] },
39
+ });
40
+ });