graphai 0.2.7 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +108 -48
  2. package/lib/experimental_agents/data_agents/index.d.ts +0 -1
  3. package/lib/experimental_agents/data_agents/index.js +1 -3
  4. package/lib/experimental_agents/graph_agents/map_agent.js +1 -1
  5. package/lib/experimental_agents/graph_agents/nested_agent.js +7 -16
  6. package/lib/experimental_agents/index.d.ts +2 -8
  7. package/lib/experimental_agents/index.js +5 -8
  8. package/lib/experimental_agents/llm_agents/groq_agent.d.ts +21 -6
  9. package/lib/experimental_agents/llm_agents/groq_agent.js +51 -17
  10. package/lib/experimental_agents/llm_agents/packages.d.ts +2 -2
  11. package/lib/experimental_agents/llm_agents/packages.js +2 -2
  12. package/lib/experimental_agents/packages.d.ts +1 -0
  13. package/lib/experimental_agents/packages.js +1 -0
  14. package/lib/experimental_agents/service_agents/fetch_agent.d.ts +62 -0
  15. package/lib/experimental_agents/service_agents/fetch_agent.js +95 -0
  16. package/lib/experimental_agents/service_agents/index.d.ts +1 -1
  17. package/lib/experimental_agents/service_agents/index.js +3 -3
  18. package/lib/experimental_agents/service_agents/packages.d.ts +2 -0
  19. package/lib/experimental_agents/service_agents/packages.js +8 -0
  20. package/lib/experimental_agents/test_agents/echo_agent.js +4 -1
  21. package/lib/experimental_agents/vanilla.d.ts +8 -0
  22. package/lib/experimental_agents/vanilla.js +26 -0
  23. package/lib/graphai.js +2 -4
  24. package/lib/node.d.ts +2 -0
  25. package/lib/node.js +38 -4
  26. package/lib/transaction_log.d.ts +1 -0
  27. package/lib/transaction_log.js +5 -0
  28. package/lib/type.d.ts +8 -4
  29. package/lib/type.js +1 -0
  30. package/lib/utils/test_utils.d.ts +3 -1
  31. package/lib/utils/test_utils.js +19 -1
  32. package/lib/validators/common.js +1 -1
  33. package/lib/vanilla_agents.d.ts +1 -0
  34. package/lib/vanilla_agents.js +17 -0
  35. package/package.json +1 -1
  36. package/lib/experimental_agents/service_agents/rss_agent.d.ts +0 -13
  37. package/lib/experimental_agents/service_agents/rss_agent.js +0 -29
package/README.md CHANGED
@@ -21,37 +21,37 @@ nodes:
21
21
  name: Sam Bankman-Fried
22
22
  query: describe the final sentence by the court for Sam Bank-Fried
23
23
  wikipedia: // Retrieve data from Wikipedia
24
- agentId: wikipediaAgent
24
+ agent: wikipediaAgent
25
25
  inputs: [source.name]
26
26
  chunks: // Break the text from Wikipedia into chunks (2048 character each with 512 overlap)
27
- agentId: stringSplitterAgent
27
+ agent: stringSplitterAgent
28
28
  inputs: [wikipedia]
29
29
  chunkEmbeddings: // Get embedding vector of each chunk
30
- agentId: stringEmbeddingsAgent
30
+ agent: stringEmbeddingsAgent
31
31
  inputs: [chunks]
32
32
  topicEmbedding: // Get embedding vector of the question
33
- agentId: stringEmbeddingsAgent
33
+ agent: stringEmbeddingsAgent
34
34
  inputs: [source.query]
35
35
  similarities: // Calculate the cosine similarity of each chunk
36
- agentId: dotProductAgent
36
+ agent: dotProductAgent
37
37
  inputs: [chunkEmbeddings, topicEmbedding]
38
38
  sortedChunks: // Sort chunks based on their similarities
39
- agentId: sortByValuesAgent
39
+ agent: sortByValuesAgent
40
40
  inputs: [chunks, similarities]
41
41
  referenceText: // Concatenate chunks up to the token limit (5000)
42
- agentId: tokenBoundStringsAgent
42
+ agent: tokenBoundStringsAgent
43
43
  inputs: [sortedChunks]
44
44
  params:
45
45
  limit: 5000
46
46
  prompt: // Generate a prompt with that reference text
47
- agentId: stringTemplateAgent
47
+ agent: stringTemplateAgent
48
48
  inputs: [source, referenceText]
49
49
  params:
50
50
  template: |-
51
51
  Using the following document, ${0}
52
52
  ${1}
53
53
  query: // retrieves the answer from GPT3.5
54
- agentId: slashGPTAgent
54
+ agent: slashGPTAgent
55
55
  params:
56
56
  manifest:
57
57
  model: gpt-3.5-turbo
@@ -64,8 +64,8 @@ flowchart TD
64
64
  source -- name --> wikipedia(wikipedia)
65
65
  source -- query --> topicEmbedding(topicEmbedding)
66
66
  wikipedia --> chunks(chunks)
67
- chunks --> chunksEmbeddings(chunksEmbeddings)
68
- chunksEmbeddings --> similarities(similarities)
67
+ chunks --> chunkEmbeddings(chunkEmbeddings)
68
+ chunkEmbeddings --> similarities(similarities)
69
69
  topicEmbedding --> similarities
70
70
  similarities --> sortedChunks(sortedChunks)
71
71
  sortedChunks --> resourceText(resourceText)
@@ -74,7 +74,7 @@ flowchart TD
74
74
  prompt --> query(query)
75
75
  ```
76
76
 
77
- Notice that the conversion of the querty text into an embedding vector and text chunks into an array of embedding vectors can be done concurrently because there is no dependency between them. GraphAI will automatically recognize it and execute them concurrently. This kind of *concurrent programing* is very difficult in traditional programming style, and GraphAI's *data flow programming* style is much better alternative.
77
+ Notice that the conversion of the query text into an embedding vector and text chunks into an array of embedding vectors can be done concurrently because there is no dependency between them. GraphAI will automatically recognize it and execute them concurrently. This kind of *concurrent programing* is very difficult in traditional programming style, and GraphAI's *data flow programming* style is much better alternative.
78
78
 
79
79
  ## Quick Install
80
80
 
@@ -94,52 +94,82 @@ A Data Flow Graph (DFG) is a JavaScript object, which defines the flow of data.
94
94
 
95
95
  A DFG consists of a collection of [nodes](#node), which contains a series of nested properties representing individual nodes in the data flow. Each node is identified by a unique key, *nodeId* (e.g., node1, node2) and can contain several predefined properties (such as params, inputs, and value) that dictate the node's behavior and its relationship with other nodes. There are two types of nodes, [computed nodes](#computed-node) and [static nodes](#static-node), which are described below.
96
96
 
97
- Connections between nodes will be established by references from one not to another, using either its "inputs" or "update" property. The values of those properties are *data sources*. A *data souce* is specified by either the nodeId (e.g., "node1"), or nodeId + propertyId ("node1.item").
97
+ ### Data Source
98
+
99
+ Connections between nodes will be established by references from one node to another, using either its "inputs" or "update" property. The values of those properties are *data sources*. A *data souce* is specified by either the nodeId (e.g., "node1"), or nodeId + propertyId (e.g., "node1.item"), index (e.g., "node1.$0", "node2.$last") or combinations (e.g., "node1.messages.$0.content").
98
100
 
99
101
  ### DFG Structure
100
102
 
101
- - 'nodes': A list of node. Required.
102
- - 'concurrency': An optional property, which specifies the maximum number of concurrent operations (agent functions to be executed at the same time). The default is 8.
103
- - 'loop': An optional property, which specifies if the graph needs to be executed multiple times. See the [Loop section below](#loop) for details.
103
+ - *nodes*: A list of node. Required.
104
+ - *concurrency*: An optional property, which specifies the maximum number of concurrent operations (agent functions to be executed at the same time). The default is 8.
105
+ - *loop*: An optional property, which specifies if the graph needs to be executed multiple times (iterations). See the [Loop section below](#loop) for details.
104
106
 
105
107
  ## Agent
106
108
 
107
- An *agent* is an abstract object which takes some inputs and generates an output asynchronously. It could be an LLM (such as GPT-4), a media generator, a database, or a REST API over HTTP. A node associated with an agent (specified by 'agentId' property) is called [computed node](#computed-node), which takes a set of inputs from other nodes, lets the agent to process it, and pushes the returned value to other nodes.
109
+ An *agent* is an abstract object which takes some inputs and generates an output asynchronously. It could be an LLM call (such as GPT-4), a media generator, a database access, or a REST API over HTTP. A node associated with an agent (specified by the *agent*'* property) is called [computed node](#computed-node), which takes a set of *inputs* from *data sources*, asks the *agent function* to process it, and makes the returned value available to other nodes.
108
110
 
109
111
  ### Agent function
110
112
 
111
- An agent function is a TypeScript function, which implements a particular *agent*. An *agent function* receives two set of parameters via AgentFunctionContext:
113
+ An *agent function* is a TypeScript function, which implements a particular *agent*, performing some computations for the associated *computed node*. An *agent function* receives a *context* (type AgentFunctionContext), which has following properties:
114
+
115
+ - *params*: agent specific parameters specified in the DFG (specified by the "params" property of the node)
116
+ - *inputs*: a set of inputs came from other nodes (specified by "inputs" property of the node).
117
+ - *debugInfo*: a set of information for debugging purposes.
118
+
119
+ There are additional optional parameters for developers of nested agents and agent filters.
120
+
121
+ - *graphData*: an optional GraphData (for nested agents)
122
+ - *agents*: AgentFunctionDictonary (for nested agents)
123
+ - *taskManager*: TaskManager (for nested agents)
124
+ - *log*: TransactionLog[] (for nested agents)
125
+ - *filterParams*: agent filter parameters (for agent filters)
126
+
127
+ ### Inline Agent Function
112
128
 
113
- - params: agent specific parameters specified in the DFG (specified by the "params" property of the node)
114
- - inputs: a set of inputs came from other nodes (specified by "inputs" property of the node).
129
+ An *inline agent function* is a simplified version of *agent function*, which is embedded in the graph (available only when the graph was described in TypeScript). An *inline agent function* receives only the *inputs* paramter as a variable length arguments.
130
+
131
+ Here is an examnple (from [weather chat](https://github.com/receptron/graphai/blob/main/samples/sample_weather.ts)):
132
+
133
+ ```typescript
134
+ messagesWithUserInput: {
135
+ // Appends the user's input to the messages.
136
+ agent: (messages: Array<any>, content: string) => [...messages, { role: "user", content }],
137
+ inputs: ["messages", "userInput"],
138
+ if: "checkInput",
139
+ },
140
+ ```
115
141
 
116
142
  ## Node
117
143
 
118
- There are two types of Node, *computed nodes* and *static nodes*. A *computed node* is associated with an *agent function*, which receives some inputs, performs some computations asynchronously then returns the result (output). A *static node* is a placeholder of a value (just like a variable in programming language), which is specified by the *value* property, injected by an external program, or is updated at the end of iteration (see the [loop](#loop)).
144
+ There are two types of Node, *computed nodes* and *static nodes*.
145
+
146
+ A *computed node* is associated with an *agent function*, which receives some inputs, performs some computations asynchronously, and returns the result (output).
147
+
148
+ A *static node* is a placeholder of a value (just like a variable in programming languages), which is initially specified by its *value* property, and can be updated by an external program (before the execution of the graph), or updated using the *update* property at the end of each iteration of a [loop](#loop) operation.
119
149
 
120
150
  ### Computed Node
121
151
 
122
- A *computed node* have following properties.
152
+ A *computed node* has following properties.
123
153
 
124
- - 'agentId': An **required** property, which specifies the id of the *agent function*.
125
- - 'params': An optional agent-specific property to control the behavior of the associated agent function.
126
- - 'inputs': An optional list of *data sources* that the current node receives the data from. This establishes a data flow where the current node can only be executed after the completion of the nodes listed under 'inputs'. If this list is empty, the associated *agent function* will be immediatley executed.
127
- - 'anyInput': An optiona boolean flag, which indicates that the associated *agent function* will be called when at least one of input data became available. Otherwise, it will wait until all the data became available.
128
- - 'retry': An optional number, which specifies the maximum number of retries to be made. If the last attempt fails, the error will be recorded.
129
- - 'timeout': An optional number, which specifies the maximum waittime in msec. If the associated agent function does not return the value in time, the "Timeout" error will be recorded. The returned value received after the time out will be discarded.
130
- - 'isResult': An optional boolean value, which indicates that the return value of this node, should be included as a property of the return value from the run() method of the GraphUI instance.
131
- - 'priority': An optional number, which specifies the priority of the execution of the associated agent (the task). Default is 0, which means "neutral". Negative numbers are allowed as well.
154
+ - *agent*: An **required** property, which specifies the id of the *agent function*, or an *inline agent function* (NOTE: this is not possible in JSON or YAML).
155
+ - *params*: An optional agent-specific property to control the behavior of the associated agent function. The top level property may reference a *data source*.
156
+ - *inputs*: An optional list of *data sources* that the current node receives the data from. This establishes a data flow where the current node can only be executed after the completion of the nodes listed under *inputs*. If this list is empty, the associated *agent function* will be immediatley executed.
157
+ - *anyInput*: An optiona boolean flag, which indicates that the associated *agent function* will be called when at least one of input data became available. Otherwise, it will wait until all the data became available.
158
+ - *retry*: An optional number, which specifies the maximum number of retries to be made. If the last attempt fails, the error will be recorded.
159
+ - *timeout*: An optional number, which specifies the maximum waittime in msec. If the associated agent function does not return the value in time, the "Timeout" error will be recorded. The returned value received after the time out will be discarded.
160
+ - *isResult*: An optional boolean value, which indicates that the return value of this node, should be included as a property of the return value from the run() method of the GraphUI instance.
161
+ - *priority*: An optional number, which specifies the priority of the execution of the associated agent (the task). Default is 0, which means "neutral". Negative numbers are allowed as well.
132
162
 
133
163
  ### Static Node
134
164
 
135
- A *static* node have following properties.
165
+ A *static* node has following properties.
136
166
 
137
- - 'value': An **required** property, which specifies the initial value of this static node (equivalent to calling the injectValue method from outside).
138
- - 'update': An optional property, which specifies the *data source* after each iteration. See the [loop](#loop) for details.
167
+ - *value*: An **required** property, which specifies the initial value of this static node (equivalent to calling the injectValue method from outside).
168
+ - *update*: An optional property, which specifies the *data source* for a [loop](#loop) operation. After each iteration, the value of this node will be updated with the data from the specified *data source*.
139
169
 
140
170
  ## Flow Control
141
171
 
142
- Since the data-flow graph must be asyclic by design, we added a few mechanism to control data flows, [nesting](#nesting), [loop](#loop), [mapping](#mapping) and [condtional flow](#conditional-flow).
172
+ Since the data-flow graph must be asyclic by design, we added a few mechanisms to control data flows, [nesting](#nesting), [loop](#loop), [mapping](#mapping) and [conditional flow](#conditional-flow).
143
173
 
144
174
  ### Nested Graph
145
175
 
@@ -152,23 +182,23 @@ nodes:
152
182
  question:
153
183
  value: "Find out which materials we need to purchase this week for Joe Smith's residential house project."
154
184
  projectId: // identifies the projectId from the question
155
- agentId: "identifierAgent"
185
+ agent: "identifierAgent"
156
186
  inputs: ["source"] // == "sourceNode.query"
157
187
  database:
158
- agentId: "nestedAgent"
188
+ agent: "nestedAgent"
159
189
  inputs: ["question", "projectId"]
160
190
  graph:
161
191
  nodes:
162
192
  schema: // retrieves the database schema for the apecified projectId
163
- agentId: "schemaAgent"
193
+ agent: "schemaAgent"
164
194
  inputs: ["$1"]
165
195
  ... // issue query to the database and build an appropriate prompt with it.
166
196
  query: // send the generated prompt to the LLM
167
- agentId: "llama3Agent"
197
+ agent: "llama3Agent"
168
198
  inputs: ["prompt"]
169
199
  isResult: true
170
200
  response: // Deliver the answer
171
- agentid: "deliveryAgent"
201
+ agent: "deliveryAgent"
172
202
  inputs: [database.query.$last.content]
173
203
  ```
174
204
 
@@ -181,7 +211,7 @@ flowchart LR
181
211
  question --> projectId(projectId)
182
212
  question --> database
183
213
  projectId --> database
184
- database[[database]] -- query --> response(responce)
214
+ database[[database]] -- query --> response(response)
185
215
  ```
186
216
 
187
217
  Here is the diagram of the child graph. Notice that two phantom nodes are automatically created to allow inner nodes to access input data from the parent graph.
@@ -198,9 +228,12 @@ This mechanism does not only allows devleoper to reuse code, but also makes it p
198
228
 
199
229
  ### Loop
200
230
 
201
- The loop is an optioal property of a graph, which has two optional properties. The *count* property specifies the number of times the graph needs to be executed and the *while* property specifies the condition required to contineu the loop in the form of node name (nodeId) or its property (nodeId.propId). Unlike JavaScript, an empty array will be treated as false.
231
+ The loop is an optional property of a graph, which has two optional properties.
202
232
 
203
- Here is an example, which performs an LLM query for each person in the list and create the list of answers. The "people" node (static), is initialized with an array of names, and the "retriever" node (computed) retrieves one name at a time, and send it to the "query" node (computed) to perform an LLM query. The "reducer" append it the array retrieved form the "result" node (static node, which is initialized as an empty array).
233
+ - *count*: Specifies the number of times the graph needs to be executed.
234
+ - *while*: Specifies the *data source* to check after the each iteration. It continues if the data from that *data source* is *true*. Unlike JavaScript, an empty array will be treated as *false*.
235
+
236
+ Here is an example, which performs an LLM query for each person in the list and create the list of answers. The "people" node (static), is initialized with an array of names, and the "retriever" node (computed) retrieves one name at a time, and sends it to the "query" node (computed) to perform an LLM query. The "reducer" append it the array retrieved form the "result" node (static node, which is initialized as an empty array).
204
237
 
205
238
  The "update" property of two static nodes ("people" and "result"), updates those properties based on the results from the previous itelation. This loop continues until the value of "people" node become an empty array.
206
239
 
@@ -216,16 +249,16 @@ nodes:
216
249
  update: reducer
217
250
  isResult: true
218
251
  retriever:
219
- agentId: shift
252
+ agent: shift
220
253
  inputs: [people]
221
254
  query:
222
- agentId: slashgpt
255
+ agent: slashgpt
223
256
  params:
224
257
  manifest:
225
258
  prompt: Describe about the person in less than 100 words
226
259
  inputs: [retriever.item]
227
260
  reducer:
228
- agentId: push
261
+ agent: push
229
262
  inputs: [result, query.content]
230
263
  ```
231
264
 
@@ -258,12 +291,12 @@ nodes:
258
291
  people:
259
292
  value: [Steve Jobs, Elon Musk, Nikola Tesla]
260
293
  retriever:
261
- agentId: "mapAgent"
294
+ agent: "mapAgent"
262
295
  inputs: ["people"]
263
296
  graph:
264
297
  nodes:
265
298
  query:
266
- agentId: slashgpt
299
+ agent: slashgpt
267
300
  params:
268
301
  manifest:
269
302
  prompt: Describe about the person in less than 100 words
@@ -283,7 +316,34 @@ flowchart LR
283
316
  ```
284
317
  ### Conditional Flow
285
318
 
286
- To be filled.
319
+ When a node has *if* property (which specifies the data source), the data flows to this node only if the value from the data source has some value.
320
+
321
+ A sample code, [weather chat](https://github.com/receptron/graphai/blob/main/samples/sample_weather.ts) uses the following *if* property to execute a block of graph, if the LLM asks to use a tool (i.e., function call).
322
+
323
+ ```typescript
324
+ tool_calls: {
325
+ // This node is activated if the LLM requests a tool call.
326
+ agent: "nestedAgent",
327
+ inputs: ["groq.choices.$0.message.tool_calls", "messagesWithFirstRes"],
328
+ if: "groq.choices.$0.message.tool_calls",
329
+ graph: {
330
+ // This graph is nested only for the readability.
331
+ ```
332
+
333
+ Even though it is not required, we strongly recommand to use it with a nested graph for the readability.
334
+
335
+ The *anyInput* property (boolean) allows the developer to "merge" multiple data flow paths into one. When the value of this property is true, the agent function associated with this node will be executed when the data from one of data sources became available.
336
+
337
+ The [weather chat](https://github.com/receptron/graphai/blob/main/samples/sample_weather.ts) sample application uses this property to continue the chat iteration either a tool was requested by LLM or not.
338
+
339
+ ```typescript
340
+ reducer: {
341
+ // Receives messages from either case.
342
+ agent: "copyAgent",
343
+ anyInput: true,
344
+ inputs: ["no_tool_calls", "tool_calls.messagesWithSecondRes"],
345
+ },
346
+ ```
287
347
 
288
348
  ## Concurrency
289
349
 
@@ -1,5 +1,4 @@
1
1
  export { totalAgent } from "../../experimental_agents/data_agents/total_agent";
2
- export { dataObjectMergeTemplateAgent } from "../../experimental_agents/data_agents/data_object_merge_template_agent";
3
2
  export { dataSumTemplateAgent } from "../../experimental_agents/data_agents/data_sum_template_agent";
4
3
  export { propertyFilterAgent } from "../../experimental_agents/data_agents/property_filter_agent";
5
4
  export { copyAgent } from "../../experimental_agents/data_agents/copy_agent";
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.copyAgent = exports.propertyFilterAgent = exports.dataSumTemplateAgent = exports.dataObjectMergeTemplateAgent = exports.totalAgent = void 0;
3
+ exports.copyAgent = exports.propertyFilterAgent = exports.dataSumTemplateAgent = exports.totalAgent = void 0;
4
4
  var total_agent_1 = require("../../experimental_agents/data_agents/total_agent");
5
5
  Object.defineProperty(exports, "totalAgent", { enumerable: true, get: function () { return total_agent_1.totalAgent; } });
6
- var data_object_merge_template_agent_1 = require("../../experimental_agents/data_agents/data_object_merge_template_agent");
7
- Object.defineProperty(exports, "dataObjectMergeTemplateAgent", { enumerable: true, get: function () { return data_object_merge_template_agent_1.dataObjectMergeTemplateAgent; } });
8
6
  var data_sum_template_agent_1 = require("../../experimental_agents/data_agents/data_sum_template_agent");
9
7
  Object.defineProperty(exports, "dataSumTemplateAgent", { enumerable: true, get: function () { return data_sum_template_agent_1.dataSumTemplateAgent; } });
10
8
  var property_filter_agent_1 = require("../../experimental_agents/data_agents/property_filter_agent");
@@ -37,7 +37,7 @@ const mapAgent = async ({ params, inputs, agents, log, taskManager, graphData })
37
37
  });
38
38
  const results = await Promise.all(runs);
39
39
  const nodeIds = Object.keys(results[0]);
40
- (0, utils_1.assert)(nodeIds.length > 0, "mapAgent: no return values (missing isResult)");
40
+ // assert(nodeIds.length > 0, "mapAgent: no return values (missing isResult)");
41
41
  const compositeResult = nodeIds.reduce((tmp, nodeId) => {
42
42
  tmp[nodeId] = results.map((result) => {
43
43
  return result[nodeId];
@@ -38,22 +38,13 @@ const nestedAgent = async ({ params, inputs, agents, log, taskManager, graphData
38
38
  }
39
39
  });
40
40
  const graphAI = new graphai_1.GraphAI(nestedGraphData, agents || {}, { taskManager });
41
- try {
42
- // Inject inputs to specified source nodes
43
- injectionTo.forEach((injectToNodeId, index) => {
44
- graphAI.injectValue(injectToNodeId, inputs[index]);
45
- });
46
- const results = await graphAI.run(false);
47
- log?.push(...graphAI.transactionLogs());
48
- return results;
49
- }
50
- catch (error) {
51
- log?.push(...graphAI.transactionLogs());
52
- if (error instanceof Error) {
53
- console.log("Error:", error.message);
54
- }
55
- throw error;
56
- }
41
+ // Inject inputs to specified source nodes
42
+ injectionTo.forEach((injectToNodeId, index) => {
43
+ graphAI.injectValue(injectToNodeId, inputs[index]);
44
+ });
45
+ const results = await graphAI.run(false);
46
+ log?.push(...graphAI.transactionLogs());
47
+ return results;
57
48
  };
58
49
  exports.nestedAgent = nestedAgent;
59
50
  const nestedAgentInfo = {
@@ -1,12 +1,6 @@
1
- export * from "./string_agents";
1
+ export * from "./vanilla";
2
+ export { dataObjectMergeTemplateAgent } from "../experimental_agents/data_agents/data_object_merge_template_agent";
2
3
  export * from "./sleeper_agents";
3
- export * from "./data_agents";
4
- export * from "./array_agents";
5
- export * from "./matrix_agents";
6
- export * from "./test_agents";
7
- export * from "./graph_agents";
8
4
  export * from "./llm_agents";
9
5
  export * from "./service_agents";
10
- export * from "./embedding_agent";
11
6
  export * from "./token_agent";
12
- export * from "./function_agent";
@@ -14,15 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./string_agents"), exports);
17
+ exports.dataObjectMergeTemplateAgent = void 0;
18
+ __exportStar(require("./vanilla"), exports);
19
+ // Agents that use npm modules will be added here.
20
+ var data_object_merge_template_agent_1 = require("../experimental_agents/data_agents/data_object_merge_template_agent");
21
+ Object.defineProperty(exports, "dataObjectMergeTemplateAgent", { enumerable: true, get: function () { return data_object_merge_template_agent_1.dataObjectMergeTemplateAgent; } });
18
22
  __exportStar(require("./sleeper_agents"), exports);
19
- __exportStar(require("./data_agents"), exports);
20
- __exportStar(require("./array_agents"), exports);
21
- __exportStar(require("./matrix_agents"), exports);
22
- __exportStar(require("./test_agents"), exports);
23
- __exportStar(require("./graph_agents"), exports);
24
23
  __exportStar(require("./llm_agents"), exports);
25
24
  __exportStar(require("./service_agents"), exports);
26
- __exportStar(require("./embedding_agent"), exports);
27
25
  __exportStar(require("./token_agent"), exports);
28
- __exportStar(require("./function_agent"), exports);
@@ -1,21 +1,36 @@
1
1
  import { AgentFunction } from "../../graphai";
2
- export declare const gloqAgent: AgentFunction<{
2
+ export declare const groqAgent: AgentFunction<{
3
3
  model: string;
4
4
  query?: string;
5
5
  system?: string;
6
- }, Record<string, any> | string, string>;
7
- declare const gloqAgentInfo: {
6
+ verbose?: boolean;
7
+ tools?: Record<string, any>;
8
+ temperature?: number;
9
+ max_tokens?: number;
10
+ tool_choice?: string | Record<string, any>;
11
+ }, Record<string, any> | string, string | Array<Record<string, any>>>;
12
+ declare const groqAgentInfo: {
8
13
  name: string;
9
14
  agent: AgentFunction<{
10
15
  model: string;
11
16
  query?: string | undefined;
12
17
  system?: string | undefined;
13
- }, string | Record<string, any>, string>;
18
+ verbose?: boolean | undefined;
19
+ tools?: Record<string, any> | undefined;
20
+ temperature?: number | undefined;
21
+ max_tokens?: number | undefined;
22
+ tool_choice?: string | Record<string, any> | undefined;
23
+ }, string | Record<string, any>, string | Record<string, any>[]>;
14
24
  mock: AgentFunction<{
15
25
  model: string;
16
26
  query?: string | undefined;
17
27
  system?: string | undefined;
18
- }, string | Record<string, any>, string>;
28
+ verbose?: boolean | undefined;
29
+ tools?: Record<string, any> | undefined;
30
+ temperature?: number | undefined;
31
+ max_tokens?: number | undefined;
32
+ tool_choice?: string | Record<string, any> | undefined;
33
+ }, string | Record<string, any>, string | Record<string, any>[]>;
19
34
  samples: never[];
20
35
  description: string;
21
36
  category: string[];
@@ -23,4 +38,4 @@ declare const gloqAgentInfo: {
23
38
  repository: string;
24
39
  license: string;
25
40
  };
26
- export default gloqAgentInfo;
41
+ export default groqAgentInfo;
@@ -1,29 +1,63 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.gloqAgent = void 0;
3
+ exports.groqAgent = void 0;
4
4
  const groq_sdk_1 = require("groq-sdk");
5
5
  const utils_1 = require("../../utils/utils");
6
6
  const groq = process.env.GROQ_API_KEY ? new groq_sdk_1.Groq({ apiKey: process.env.GROQ_API_KEY }) : undefined;
7
- const gloqAgent = async ({ params, inputs }) => {
7
+ //
8
+ // This agent takes two optional inputs, and following parameters.
9
+ // inputs:
10
+ // - [0]: query string (typically from the user), optional
11
+ // - [1]: array of messages from previous conversation, optional
12
+ //
13
+ // params:
14
+ // - model: LLM model (Llama3-8b-8192, Llama3-70b-8192, Mixtral-8x7b-32768), required.
15
+ // - query: Additional query string from the app to prepend the query from the user, optional.
16
+ // - system: System prompt (ignored if inputs[1] is specified), optional
17
+ // - tools: Function definitions, optional
18
+ // - tool_choice: Tool choice parameter, optional (default = "auto")
19
+ // - temperature: Controls randomness of responses, optional (default = 0.7)
20
+ // - max_tokens: The maximum number of tokens that the model can process in a single response, optional.
21
+ // - verbose: dumps the message array to the debug console, before sending it the LLM.
22
+ //
23
+ // https://console.groq.com/docs/quickstart
24
+ //
25
+ const groqAgent = async ({ params, inputs }) => {
8
26
  (0, utils_1.assert)(groq !== undefined, "The GROQ_API_KEY environment variable is missing.");
9
- const query = params?.query ? [params.query] : [];
10
- const content = query.concat(inputs).join("\n");
11
- const messages = params?.system ? [{ role: "system", content: params.system }] : [];
12
- messages.push({
13
- role: "user",
14
- content,
15
- });
16
- const result = await groq.chat.completions.create({
27
+ const { verbose, query, system, tools, tool_choice, max_tokens, temperature } = params;
28
+ const [input_query, previous_messages] = inputs;
29
+ // Notice that we ignore params.system if previous_message exists.
30
+ const messages = previous_messages && Array.isArray(previous_messages) ? previous_messages : system ? [{ role: "system", content: system }] : [];
31
+ const content = (query ? [query] : []).concat(input_query ? [input_query] : []).join("\n");
32
+ if (content) {
33
+ messages.push({
34
+ role: "user",
35
+ content,
36
+ });
37
+ }
38
+ if (verbose) {
39
+ console.log(messages);
40
+ }
41
+ const options = {
17
42
  messages,
18
43
  model: params.model,
19
- });
44
+ temperature: temperature ?? 0.7,
45
+ };
46
+ if (max_tokens) {
47
+ options.max_tokens = max_tokens;
48
+ }
49
+ if (tools) {
50
+ options.tools = tools;
51
+ options.tool_choice = tool_choice ?? "auto";
52
+ }
53
+ const result = await groq.chat.completions.create(options);
20
54
  return result;
21
55
  };
22
- exports.gloqAgent = gloqAgent;
23
- const gloqAgentInfo = {
24
- name: "gloqAgent",
25
- agent: exports.gloqAgent,
26
- mock: exports.gloqAgent,
56
+ exports.groqAgent = groqAgent;
57
+ const groqAgentInfo = {
58
+ name: "groqAgent",
59
+ agent: exports.groqAgent,
60
+ mock: exports.groqAgent,
27
61
  samples: [],
28
62
  description: "Groq Agent",
29
63
  category: ["llm"],
@@ -31,4 +65,4 @@ const gloqAgentInfo = {
31
65
  repository: "https://github.com/receptron/graphai",
32
66
  license: "MIT",
33
67
  };
34
- exports.default = gloqAgentInfo;
68
+ exports.default = groqAgentInfo;
@@ -1,3 +1,3 @@
1
- import gloqAgent from "../../experimental_agents/llm_agents/groq_agent";
1
+ import groqAgent from "../../experimental_agents/llm_agents/groq_agent";
2
2
  import slashGPTAgent from "../../experimental_agents/llm_agents/slashgpt_agent";
3
- export { gloqAgent, slashGPTAgent };
3
+ export { groqAgent, slashGPTAgent };
@@ -3,8 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.slashGPTAgent = exports.gloqAgent = void 0;
6
+ exports.slashGPTAgent = exports.groqAgent = void 0;
7
7
  const groq_agent_1 = __importDefault(require("../../experimental_agents/llm_agents/groq_agent"));
8
- exports.gloqAgent = groq_agent_1.default;
8
+ exports.groqAgent = groq_agent_1.default;
9
9
  const slashgpt_agent_1 = __importDefault(require("../../experimental_agents/llm_agents/slashgpt_agent"));
10
10
  exports.slashGPTAgent = slashgpt_agent_1.default;
@@ -6,6 +6,7 @@ export * from "./matrix_agents/packages";
6
6
  export * from "./test_agents/packages";
7
7
  export * from "./graph_agents/packages";
8
8
  export * from "./llm_agents/packages";
9
+ export * from "./service_agents/packages";
9
10
  import stringEmbeddingsAgent from "./embedding_agent";
10
11
  import tokenBoundStringsAgent from "./token_agent";
11
12
  import functionAgentInfo from "./function_agent";
@@ -26,6 +26,7 @@ __exportStar(require("./matrix_agents/packages"), exports);
26
26
  __exportStar(require("./test_agents/packages"), exports);
27
27
  __exportStar(require("./graph_agents/packages"), exports);
28
28
  __exportStar(require("./llm_agents/packages"), exports);
29
+ __exportStar(require("./service_agents/packages"), exports);
29
30
  const embedding_agent_1 = __importDefault(require("./embedding_agent"));
30
31
  exports.stringEmbeddingsAgent = embedding_agent_1.default;
31
32
  const token_agent_1 = __importDefault(require("./token_agent"));
@@ -0,0 +1,62 @@
1
+ import { AgentFunction } from "../../graphai";
2
+ export declare const fetchAgent: AgentFunction<{
3
+ debug?: boolean;
4
+ type?: string;
5
+ returnErrorResult?: boolean;
6
+ }, any, any>;
7
+ declare const fetchAgentInfo: {
8
+ name: string;
9
+ agent: AgentFunction<{
10
+ debug?: boolean | undefined;
11
+ type?: string | undefined;
12
+ returnErrorResult?: boolean | undefined;
13
+ }, any, any>;
14
+ mock: AgentFunction<{
15
+ debug?: boolean | undefined;
16
+ type?: string | undefined;
17
+ returnErrorResult?: boolean | undefined;
18
+ }, any, any>;
19
+ samples: ({
20
+ inputs: (string | {
21
+ foo: string;
22
+ "x-myHeader"?: undefined;
23
+ } | {
24
+ "x-myHeader": string;
25
+ foo?: undefined;
26
+ })[];
27
+ params: {
28
+ debug: boolean;
29
+ };
30
+ result: {
31
+ method: string;
32
+ url: string;
33
+ headers: {
34
+ "x-myHeader": string;
35
+ "Content-Type"?: undefined;
36
+ };
37
+ body: undefined;
38
+ };
39
+ } | {
40
+ inputs: (string | {
41
+ foo: string;
42
+ } | undefined)[];
43
+ params: {
44
+ debug: boolean;
45
+ };
46
+ result: {
47
+ method: string;
48
+ url: string;
49
+ headers: {
50
+ "Content-Type": string;
51
+ "x-myHeader"?: undefined;
52
+ };
53
+ body: string;
54
+ };
55
+ })[];
56
+ description: string;
57
+ category: string[];
58
+ author: string;
59
+ repository: string;
60
+ license: string;
61
+ };
62
+ export default fetchAgentInfo;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchAgent = void 0;
4
+ const xml2js_1 = require("xml2js");
5
+ const fetchAgent = async ({ inputs, params }) => {
6
+ const [baseUrl, queryParams, baseHeaders, body] = inputs;
7
+ const url = new URL(baseUrl);
8
+ const headers = baseHeaders ? { ...baseHeaders } : {};
9
+ if (queryParams) {
10
+ const params = new URLSearchParams(queryParams);
11
+ url.search = params.toString();
12
+ }
13
+ if (body) {
14
+ headers["Content-Type"] = "application/json";
15
+ }
16
+ const fetchOptions = {
17
+ method: body ? "POST" : "GET",
18
+ headers: new Headers(headers),
19
+ body: body ? JSON.stringify(body) : undefined,
20
+ };
21
+ if (params?.debug) {
22
+ return {
23
+ url: url.toString(),
24
+ method: fetchOptions.method,
25
+ headers,
26
+ body: fetchOptions.body,
27
+ };
28
+ }
29
+ const response = await fetch(url.toString(), fetchOptions);
30
+ if (!response.ok) {
31
+ const status = response.status;
32
+ const error = await response.text();
33
+ if (params?.returnErrorResult) {
34
+ return { status, error };
35
+ }
36
+ throw new Error(`HTTP error! Status: ${status} ${error} ${url.toString()}`);
37
+ }
38
+ const result = await (async () => {
39
+ const type = params?.type ?? "json";
40
+ if (type === "json") {
41
+ return await response.json();
42
+ }
43
+ else if (type === "xml") {
44
+ const xmlData = await response.text();
45
+ return await (0, xml2js_1.parseStringPromise)(xmlData, { explicitArray: false, mergeAttrs: true });
46
+ }
47
+ else if (type === "text") {
48
+ return response.text();
49
+ }
50
+ throw new Error(`Unknown Type! ${type}`);
51
+ })();
52
+ return result;
53
+ };
54
+ exports.fetchAgent = fetchAgent;
55
+ const fetchAgentInfo = {
56
+ name: "fetchAgent",
57
+ agent: exports.fetchAgent,
58
+ mock: exports.fetchAgent,
59
+ samples: [
60
+ {
61
+ inputs: ["https://www.google.com", { foo: "bar" }, { "x-myHeader": "secret" }],
62
+ params: {
63
+ debug: true,
64
+ },
65
+ result: {
66
+ method: "GET",
67
+ url: "https://www.google.com/?foo=bar",
68
+ headers: {
69
+ "x-myHeader": "secret",
70
+ },
71
+ body: undefined,
72
+ },
73
+ },
74
+ {
75
+ inputs: ["https://www.google.com", undefined, undefined, { foo: "bar" }],
76
+ params: {
77
+ debug: true,
78
+ },
79
+ result: {
80
+ method: "POST",
81
+ url: "https://www.google.com/",
82
+ headers: {
83
+ "Content-Type": "application/json",
84
+ },
85
+ body: "{\"foo\":\"bar\"}",
86
+ },
87
+ },
88
+ ],
89
+ description: "Retrieves JSON data from the specified URL",
90
+ category: ["data"],
91
+ author: "Receptron",
92
+ repository: "https://github.com/receptron/graphai",
93
+ license: "MIT",
94
+ };
95
+ exports.default = fetchAgentInfo;
@@ -1,2 +1,2 @@
1
1
  export { wikipediaAgent } from "../../experimental_agents/service_agents/wikipedia";
2
- export { rssAgent } from "../../experimental_agents/service_agents/rss_agent";
2
+ export { fetchAgent } from "../../experimental_agents/service_agents/fetch_agent";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rssAgent = exports.wikipediaAgent = void 0;
3
+ exports.fetchAgent = exports.wikipediaAgent = void 0;
4
4
  var wikipedia_1 = require("../../experimental_agents/service_agents/wikipedia");
5
5
  Object.defineProperty(exports, "wikipediaAgent", { enumerable: true, get: function () { return wikipedia_1.wikipediaAgent; } });
6
- var rss_agent_1 = require("../../experimental_agents/service_agents/rss_agent");
7
- Object.defineProperty(exports, "rssAgent", { enumerable: true, get: function () { return rss_agent_1.rssAgent; } });
6
+ var fetch_agent_1 = require("../../experimental_agents/service_agents/fetch_agent");
7
+ Object.defineProperty(exports, "fetchAgent", { enumerable: true, get: function () { return fetch_agent_1.fetchAgent; } });
@@ -0,0 +1,2 @@
1
+ import fetchAgent from "../../experimental_agents/service_agents/fetch_agent";
2
+ export { fetchAgent };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchAgent = void 0;
7
+ const fetch_agent_1 = __importDefault(require("../../experimental_agents/service_agents/fetch_agent"));
8
+ exports.fetchAgent = fetch_agent_1.default;
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.echoAgent = void 0;
4
- const echoAgent = async ({ params }) => {
4
+ const echoAgent = async ({ params, filterParams }) => {
5
+ if (params.filterParams) {
6
+ return filterParams;
7
+ }
5
8
  return params;
6
9
  };
7
10
  exports.echoAgent = echoAgent;
@@ -0,0 +1,8 @@
1
+ export * from "./string_agents";
2
+ export * from "./array_agents";
3
+ export * from "./matrix_agents";
4
+ export * from "./test_agents";
5
+ export * from "./graph_agents";
6
+ export * from "./function_agent";
7
+ export * from "./embedding_agent";
8
+ export * from "./data_agents";
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ // This file adds agents that runs in pure JavaScript without any external npm modules.
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ // Please refrain from adding agents that require npm. Those should be added to the index.ts.
19
+ __exportStar(require("./string_agents"), exports);
20
+ __exportStar(require("./array_agents"), exports);
21
+ __exportStar(require("./matrix_agents"), exports);
22
+ __exportStar(require("./test_agents"), exports);
23
+ __exportStar(require("./graph_agents"), exports);
24
+ __exportStar(require("./function_agent"), exports);
25
+ __exportStar(require("./embedding_agent"), exports);
26
+ __exportStar(require("./data_agents"), exports);
package/lib/graphai.js CHANGED
@@ -52,15 +52,13 @@ class GraphAI {
52
52
  const node = this.nodes[nodeId];
53
53
  if (node?.isStaticNode) {
54
54
  const value = node?.value;
55
- const update = node?.update;
56
55
  if (value) {
57
56
  this.injectValue(nodeId, value, nodeId);
58
57
  }
58
+ const update = node?.update;
59
59
  if (update && previousResults) {
60
60
  const result = this.getValueFromResults(update, previousResults);
61
- if (result) {
62
- this.injectValue(nodeId, result, update);
63
- }
61
+ this.injectValue(nodeId, result, update);
64
62
  }
65
63
  }
66
64
  });
package/lib/node.d.ts CHANGED
@@ -16,6 +16,7 @@ export declare class ComputedNode extends Node {
16
16
  readonly graphId: string;
17
17
  readonly isResult: boolean;
18
18
  readonly params: NodeDataParams;
19
+ private readonly dynamicParams;
19
20
  readonly nestedGraph?: GraphData;
20
21
  readonly retryLimit: number;
21
22
  retryCount: number;
@@ -28,6 +29,7 @@ export declare class ComputedNode extends Node {
28
29
  readonly anyInput: boolean;
29
30
  dataSources: Array<DataSource>;
30
31
  pendings: Set<string>;
32
+ private ifSource?;
31
33
  readonly isStaticNode = false;
32
34
  readonly isComputedNode = true;
33
35
  constructor(graphId: string, nodeId: string, data: ComputedNodeData, graph: GraphAI);
package/lib/node.js CHANGED
@@ -44,8 +44,9 @@ class ComputedNode extends Node {
44
44
  }
45
45
  else {
46
46
  (0, utils_2.assert)(typeof data.agent === "function", "agent must be either string or function");
47
+ const agent = data.agent;
47
48
  this.agentFunction = async ({ inputs }) => {
48
- return data.agent(...inputs);
49
+ return agent(...inputs);
49
50
  };
50
51
  }
51
52
  this.retryLimit = data.retry ?? graph.retryLimit ?? 0;
@@ -55,6 +56,23 @@ class ComputedNode extends Node {
55
56
  this.anyInput = data.anyInput ?? false;
56
57
  this.dataSources = (data.inputs ?? []).map((input) => (0, utils_2.parseNodeName)(input));
57
58
  this.pendings = new Set(this.dataSources.filter((source) => source.nodeId).map((source) => source.nodeId));
59
+ if (data.if) {
60
+ this.ifSource = (0, utils_2.parseNodeName)(data.if);
61
+ (0, utils_2.assert)(!!this.ifSource.nodeId, `Invalid data source ${data.if}`);
62
+ this.pendings.add(this.ifSource.nodeId);
63
+ }
64
+ const regex = /^\$\{([^{}]+)\}$/;
65
+ this.dynamicParams = Object.keys(this.params).reduce((tmp, key) => {
66
+ const value = this.params[key];
67
+ const match = typeof value === "string" ? value.match(regex) : null;
68
+ if (match) {
69
+ const dataSource = (0, utils_2.parseNodeName)(match[1]);
70
+ tmp[key] = dataSource;
71
+ (0, utils_2.assert)(!!dataSource.nodeId, `Invalid data source ${key}:${value}`);
72
+ this.pendings.add(dataSource.nodeId);
73
+ }
74
+ return tmp;
75
+ }, {});
58
76
  this.log.initForComputedNode(this);
59
77
  }
60
78
  getAgentId() {
@@ -70,6 +88,15 @@ class ComputedNode extends Node {
70
88
  return result === undefined ? count : count + 1;
71
89
  }, 0);
72
90
  if (!this.anyInput || counter > 0) {
91
+ if (this.ifSource) {
92
+ const [condition] = this.graph.resultsOf([this.ifSource]);
93
+ if (!condition) {
94
+ this.state = type_1.NodeState.Skipped;
95
+ this.log.onSkipped(this, this.graph);
96
+ return false;
97
+ }
98
+ return true;
99
+ }
73
100
  return true;
74
101
  }
75
102
  }
@@ -175,14 +202,20 @@ class ComputedNode extends Node {
175
202
  try {
176
203
  const callback = this.agentFunction ?? this.graph.getCallback(this.agentId);
177
204
  const localLog = [];
205
+ const params = Object.keys(this.dynamicParams).reduce((tmp, key) => {
206
+ const [result] = this.graph.resultsOf([this.dynamicParams[key]]);
207
+ tmp[key] = result;
208
+ return tmp;
209
+ }, { ...this.params });
178
210
  const context = {
179
- params: this.params,
211
+ params: params,
180
212
  inputs: previousResults,
181
213
  debugInfo: {
182
214
  nodeId: this.nodeId,
183
215
  retry: this.retryCount,
184
216
  verbose: this.graph.verbose,
185
217
  },
218
+ filterParams: {},
186
219
  log: localLog,
187
220
  };
188
221
  // NOTE: We use the existence of graph object in the agent-specific params to determine
@@ -225,8 +258,9 @@ class ComputedNode extends Node {
225
258
  // the retry if specified.
226
259
  errorProcess(error, transactionId) {
227
260
  if (error instanceof Error && error.message !== utils_1.strIntentionalError) {
228
- console.error(this.agentId + ": error");
229
- console.error(error);
261
+ console.error(`<-- ${this.nodeId}, ${this.agentId}`);
262
+ console.log(error);
263
+ console.log("-->");
230
264
  }
231
265
  if (!this.isCurrentTransaction(transactionId)) {
232
266
  console.log(`-- ${this.nodeId}: transactionId mismatch(error)`);
@@ -25,4 +25,5 @@ export declare class TransactionLog {
25
25
  beforeExecute(node: ComputedNode, graph: GraphAI, transactionId: number, inputs: ResultData[]): void;
26
26
  beforeAddTask(node: ComputedNode, graph: GraphAI): void;
27
27
  onError(node: ComputedNode, graph: GraphAI, errorMessage: string): void;
28
+ onSkipped(node: ComputedNode, graph: GraphAI): void;
28
29
  }
@@ -57,5 +57,10 @@ class TransactionLog {
57
57
  graph.setLoopLog(this);
58
58
  graph.updateLog(this);
59
59
  }
60
+ onSkipped(node, graph) {
61
+ this.state = node.state;
62
+ graph.setLoopLog(this);
63
+ graph.updateLog(this);
64
+ }
60
65
  }
61
66
  exports.TransactionLog = TransactionLog;
package/lib/type.d.ts CHANGED
@@ -7,9 +7,10 @@ export declare enum NodeState {
7
7
  Failed = "failed",
8
8
  TimedOut = "timed-out",
9
9
  Completed = "completed",
10
- Injected = "injected"
10
+ Injected = "injected",
11
+ Skipped = "skipped"
11
12
  }
12
- export type DefaultResultData = Record<string, any> | string | number | Array<DefaultResultData>;
13
+ export type DefaultResultData = Record<string, any> | string | number | boolean | Array<DefaultResultData>;
13
14
  export type DefaultInputData = Record<string, any>;
14
15
  export type ResultData<ResultType = DefaultResultData> = ResultType | undefined;
15
16
  export type ResultDataDictonary<ResultType = DefaultResultData> = Record<string, ResultData<ResultType>>;
@@ -25,13 +26,15 @@ export type StaticNodeData = {
25
26
  update?: string;
26
27
  isResult?: boolean;
27
28
  };
29
+ export type AgentNamelessFunction = (...param: any[]) => unknown;
28
30
  export type ComputedNodeData = {
29
- agent: string | any;
31
+ agent: string | AgentNamelessFunction;
30
32
  inputs?: Array<any>;
31
33
  anyInput?: boolean;
32
34
  params?: NodeDataParams;
33
35
  retry?: number;
34
36
  timeout?: number;
37
+ if?: string;
35
38
  graph?: GraphData;
36
39
  isResult?: boolean;
37
40
  priority?: number;
@@ -59,8 +62,9 @@ export type AgentFunctionContext<ParamsType = DefaultParamsType, InputDataType =
59
62
  };
60
63
  graphData?: GraphData | string;
61
64
  agents?: AgentFunctionDictonary;
62
- log?: TransactionLog[];
63
65
  taskManager?: TaskManager;
66
+ filterParams: Record<string, any>;
67
+ log?: TransactionLog[];
64
68
  };
65
69
  export type AgentFunction<ParamsType = DefaultParamsType, ResultType = DefaultResultData, InputDataType = DefaultInputData> = (context: AgentFunctionContext<ParamsType, InputDataType>) => Promise<ResultData<ResultType>>;
66
70
  export type AgentFilterFunction<ParamsType = DefaultParamsType, ResultType = DefaultResultData, InputDataType = DefaultInputData> = (context: AgentFunctionContext<ParamsType, InputDataType>, agent: AgentFunction) => Promise<ResultData<ResultType>>;
package/lib/type.js CHANGED
@@ -10,4 +10,5 @@ var NodeState;
10
10
  NodeState["TimedOut"] = "timed-out";
11
11
  NodeState["Completed"] = "completed";
12
12
  NodeState["Injected"] = "injected";
13
+ NodeState["Skipped"] = "skipped";
13
14
  })(NodeState || (exports.NodeState = NodeState = {}));
@@ -1,4 +1,4 @@
1
- import { AgentFunctionInfo } from "../type";
1
+ import { AgentFunctionInfo, AgentFunctionContext, AgentFunction, AgentFilterInfo, ResultData } from "../type";
2
2
  export declare const defaultTestContext: {
3
3
  debugInfo: {
4
4
  nodeId: string;
@@ -6,7 +6,9 @@ export declare const defaultTestContext: {
6
6
  verbose: boolean;
7
7
  };
8
8
  params: {};
9
+ filterParams: {};
9
10
  agents: {};
10
11
  log: never[];
11
12
  };
12
13
  export declare const agentTestRunner: (agentInfo: AgentFunctionInfo) => Promise<void>;
14
+ export declare const agentFilterRunnerBuilder: (__agentFilters: AgentFilterInfo[]) => (context: AgentFunctionContext, agent: AgentFunction) => Promise<ResultData>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.agentTestRunner = exports.defaultTestContext = void 0;
6
+ exports.agentFilterRunnerBuilder = exports.agentTestRunner = exports.defaultTestContext = void 0;
7
7
  const node_assert_1 = __importDefault(require("node:assert"));
8
8
  const node_test_1 = __importDefault(require("node:test"));
9
9
  exports.defaultTestContext = {
@@ -13,6 +13,7 @@ exports.defaultTestContext = {
13
13
  verbose: true,
14
14
  },
15
15
  params: {},
16
+ filterParams: {},
16
17
  agents: {},
17
18
  log: [],
18
19
  };
@@ -37,3 +38,20 @@ const agentTestRunner = async (agentInfo) => {
37
38
  }
38
39
  };
39
40
  exports.agentTestRunner = agentTestRunner;
41
+ // for agent and agent filter.
42
+ const agentFilterRunnerBuilder = (__agentFilters) => {
43
+ const agentFilters = __agentFilters;
44
+ const agentFilterRunner = (context, agent) => {
45
+ let index = 0;
46
+ const next = (context) => {
47
+ const agentFilter = agentFilters[index++];
48
+ if (agentFilter) {
49
+ return agentFilter.agent(context, next);
50
+ }
51
+ return agent(context);
52
+ };
53
+ return next(context);
54
+ };
55
+ return agentFilterRunner;
56
+ };
57
+ exports.agentFilterRunnerBuilder = agentFilterRunnerBuilder;
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.staticNodeAttributeKeys = exports.computedNodeAttributeKeys = exports.graphDataAttributeKeys = void 0;
4
4
  exports.graphDataAttributeKeys = ["nodes", "concurrency", "agentId", "loop", "verbose", "version"];
5
- exports.computedNodeAttributeKeys = ["inputs", "anyInput", "params", "retry", "timeout", "agent", "graph", "isResult", "priority"];
5
+ exports.computedNodeAttributeKeys = ["inputs", "anyInput", "params", "retry", "timeout", "agent", "graph", "isResult", "priority", "if"];
6
6
  exports.staticNodeAttributeKeys = ["value", "update", "isResult"];
@@ -0,0 +1 @@
1
+ export * from "./experimental_agents/vanilla";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./experimental_agents/vanilla"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphai",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Asynchronous data flow execution engine for agentic AI apps.",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -1,13 +0,0 @@
1
- import { AgentFunction } from "../../graphai";
2
- export declare const rssAgent: AgentFunction<undefined, any, string>;
3
- declare const rssAgentInfo: {
4
- name: string;
5
- agent: AgentFunction<undefined, any, string>;
6
- mock: AgentFunction<undefined, any, string>;
7
- description: string;
8
- category: string[];
9
- author: string;
10
- repository: string;
11
- license: string;
12
- };
13
- export default rssAgentInfo;
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rssAgent = void 0;
4
- const xml2js_1 = require("xml2js");
5
- const rssAgent = async ({ inputs }) => {
6
- const url = inputs[0];
7
- try {
8
- const response = await fetch(url);
9
- const xmlData = await response.text();
10
- const jsonData = await (0, xml2js_1.parseStringPromise)(xmlData, { explicitArray: false, mergeAttrs: true });
11
- return jsonData;
12
- }
13
- catch (error) {
14
- console.log(error);
15
- throw error;
16
- }
17
- };
18
- exports.rssAgent = rssAgent;
19
- const rssAgentInfo = {
20
- name: "rssAgent",
21
- agent: exports.rssAgent,
22
- mock: exports.rssAgent,
23
- description: "Retrieves XML data from RSS feed and convert it to JSON",
24
- category: ["data"],
25
- author: "Receptron",
26
- repository: "https://github.com/receptron/graphai",
27
- license: "MIT",
28
- };
29
- exports.default = rssAgentInfo;