mcpgraph 0.1.15 → 0.1.17
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 +61 -1
- package/dist/api.d.ts +13 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +40 -0
- package/dist/api.js.map +1 -1
- package/dist/config/expression-validator.d.ts +12 -0
- package/dist/config/expression-validator.d.ts.map +1 -0
- package/dist/config/expression-validator.js +77 -0
- package/dist/config/expression-validator.js.map +1 -0
- package/dist/config/parser.d.ts.map +1 -1
- package/dist/config/parser.js +9 -0
- package/dist/config/parser.js.map +1 -1
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +5 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/execution/context.d.ts +27 -3
- package/dist/execution/context.d.ts.map +1 -1
- package/dist/execution/context.js +52 -9
- package/dist/execution/context.js.map +1 -1
- package/dist/execution/executor.d.ts.map +1 -1
- package/dist/execution/executor.js +34 -12
- package/dist/execution/executor.js.map +1 -1
- package/dist/execution/nodes/entry-executor.d.ts.map +1 -1
- package/dist/execution/nodes/entry-executor.js +1 -2
- package/dist/execution/nodes/entry-executor.js.map +1 -1
- package/dist/execution/nodes/exit-executor.d.ts +1 -1
- package/dist/execution/nodes/exit-executor.d.ts.map +1 -1
- package/dist/execution/nodes/exit-executor.js +9 -7
- package/dist/execution/nodes/exit-executor.js.map +1 -1
- package/dist/execution/nodes/mcp-tool-executor.d.ts +1 -1
- package/dist/execution/nodes/mcp-tool-executor.d.ts.map +1 -1
- package/dist/execution/nodes/mcp-tool-executor.js +5 -4
- package/dist/execution/nodes/mcp-tool-executor.js.map +1 -1
- package/dist/execution/nodes/switch-executor.d.ts +1 -1
- package/dist/execution/nodes/switch-executor.d.ts.map +1 -1
- package/dist/execution/nodes/switch-executor.js +13 -8
- package/dist/execution/nodes/switch-executor.js.map +1 -1
- package/dist/execution/nodes/transform-executor.d.ts +1 -1
- package/dist/execution/nodes/transform-executor.d.ts.map +1 -1
- package/dist/execution/nodes/transform-executor.js +5 -4
- package/dist/execution/nodes/transform-executor.js.map +1 -1
- package/dist/expressions/json-logic.d.ts +11 -2
- package/dist/expressions/json-logic.d.ts.map +1 -1
- package/dist/expressions/json-logic.js +98 -16
- package/dist/expressions/json-logic.js.map +1 -1
- package/dist/expressions/jsonata-extensions.d.ts +10 -0
- package/dist/expressions/jsonata-extensions.d.ts.map +1 -0
- package/dist/expressions/jsonata-extensions.js +69 -0
- package/dist/expressions/jsonata-extensions.js.map +1 -0
- package/dist/expressions/jsonata.d.ts +8 -1
- package/dist/expressions/jsonata.d.ts.map +1 -1
- package/dist/expressions/jsonata.js +72 -12
- package/dist/expressions/jsonata.js.map +1 -1
- package/dist/types/config.d.ts +5 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/execution.d.ts +1 -1
- package/dist/types/execution.d.ts.map +1 -1
- package/docs/design.md +21 -2
- package/docs/implementation.md +15 -6
- package/docs/introspection-debugging.md +28 -1
- package/examples/api-usage.ts +54 -1
- package/examples/loop_example.yaml +84 -0
- package/package.json +1 -1
|
@@ -5,19 +5,22 @@
|
|
|
5
5
|
import jsonLogic from "json-logic-js";
|
|
6
6
|
import jsonata from "jsonata";
|
|
7
7
|
import { logger } from "../logger.js";
|
|
8
|
+
import { registerHistoryFunctions } from "./jsonata-extensions.js";
|
|
9
|
+
import { validateJsonataSyntax } from "./jsonata.js";
|
|
8
10
|
/**
|
|
9
11
|
* Evaluate a JSON Logic rule with the given context data
|
|
10
12
|
* @param rule - JSON Logic rule (can be any valid JSON Logic structure)
|
|
11
13
|
* @param context - Context data object to evaluate the rule against
|
|
12
|
-
* @param
|
|
14
|
+
* @param history - Execution history for history functions
|
|
15
|
+
* @param currentIndex - Current execution index for history functions
|
|
13
16
|
* @returns Boolean result of the rule evaluation
|
|
14
17
|
*/
|
|
15
|
-
export async function evaluateJsonLogic(rule, context,
|
|
18
|
+
export async function evaluateJsonLogic(rule, context, history, currentIndex) {
|
|
16
19
|
try {
|
|
17
20
|
logger.debug(`Evaluating JSON Logic rule: ${JSON.stringify(rule)}`);
|
|
18
21
|
logger.debug(`Context keys: ${Object.keys(context).join(", ")}`);
|
|
19
22
|
// Pre-process the rule: replace all var operations with their JSONata-evaluated values
|
|
20
|
-
const processedRule = await preprocessJsonLogicRule(rule, context,
|
|
23
|
+
const processedRule = await preprocessJsonLogicRule(rule, context, history, currentIndex);
|
|
21
24
|
// Now apply the processed rule (all var operations have been replaced with values)
|
|
22
25
|
const result = jsonLogic.apply(processedRule, context);
|
|
23
26
|
logger.debug(`JSON Logic result: ${result}`);
|
|
@@ -25,28 +28,47 @@ export async function evaluateJsonLogic(rule, context, previousNodeId) {
|
|
|
25
28
|
return Boolean(result);
|
|
26
29
|
}
|
|
27
30
|
catch (error) {
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
// Extract detailed error message
|
|
32
|
+
let errorMessage;
|
|
33
|
+
if (error instanceof Error) {
|
|
34
|
+
errorMessage = error.message || error.toString();
|
|
35
|
+
if (errorMessage === '[object Object]' || !errorMessage) {
|
|
36
|
+
errorMessage = error.toString();
|
|
37
|
+
if (error.stack) {
|
|
38
|
+
errorMessage = error.stack.split('\n')[0] || errorMessage;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (error && typeof error === 'object') {
|
|
43
|
+
const errorObj = error;
|
|
44
|
+
if (errorObj.message && typeof errorObj.message === 'string') {
|
|
45
|
+
errorMessage = errorObj.message;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
errorMessage = JSON.stringify(error, null, 2);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
errorMessage = String(error);
|
|
53
|
+
}
|
|
54
|
+
logger.error(`JSON Logic evaluation error: ${errorMessage}`);
|
|
55
|
+
logger.error(`Rule: ${JSON.stringify(rule, null, 2)}`);
|
|
56
|
+
logger.error(`Context keys: ${Object.keys(context).join(', ')}`);
|
|
57
|
+
throw new Error(`JSON Logic evaluation failed: ${errorMessage}\nRule: ${JSON.stringify(rule, null, 2)}`);
|
|
30
58
|
}
|
|
31
59
|
}
|
|
32
60
|
/**
|
|
33
61
|
* Recursively pre-process JSON Logic rule, replacing var operations with JSONata-evaluated values
|
|
34
62
|
*/
|
|
35
|
-
async function preprocessJsonLogicRule(rule, context,
|
|
63
|
+
async function preprocessJsonLogicRule(rule, context, history, currentIndex) {
|
|
36
64
|
// If rule is a var operation, evaluate it with JSONata and return the value
|
|
37
65
|
if (typeof rule === "object" && rule !== null && "var" in rule && Object.keys(rule).length === 1) {
|
|
38
66
|
const path = rule.var;
|
|
39
67
|
logger.debug(`Evaluating var operation: "${path}" as JSONata expression`);
|
|
40
68
|
try {
|
|
41
69
|
const expr = jsonata(path);
|
|
42
|
-
// Register
|
|
43
|
-
|
|
44
|
-
expr.registerFunction("previousNode", () => {
|
|
45
|
-
const previousOutput = context[previousNodeId];
|
|
46
|
-
logger.debug(`$previousNode() returning output from node: ${previousNodeId}`);
|
|
47
|
-
return previousOutput !== undefined ? previousOutput : null;
|
|
48
|
-
}, "<:o>");
|
|
49
|
-
}
|
|
70
|
+
// Register history access functions
|
|
71
|
+
registerHistoryFunctions(expr, history, currentIndex);
|
|
50
72
|
const result = await expr.evaluate(context);
|
|
51
73
|
logger.debug(`JSONata evaluation result: ${JSON.stringify(result)}`);
|
|
52
74
|
return result;
|
|
@@ -58,17 +80,77 @@ async function preprocessJsonLogicRule(rule, context, previousNodeId) {
|
|
|
58
80
|
}
|
|
59
81
|
// If rule is an array, recursively process each element
|
|
60
82
|
if (Array.isArray(rule)) {
|
|
61
|
-
return Promise.all(rule.map(item => preprocessJsonLogicRule(item, context,
|
|
83
|
+
return Promise.all(rule.map(item => preprocessJsonLogicRule(item, context, history, currentIndex)));
|
|
62
84
|
}
|
|
63
85
|
// If rule is an object, recursively process each property
|
|
64
86
|
if (typeof rule === "object" && rule !== null) {
|
|
65
87
|
const result = {};
|
|
66
88
|
for (const [key, value] of Object.entries(rule)) {
|
|
67
|
-
result[key] = await preprocessJsonLogicRule(value, context,
|
|
89
|
+
result[key] = await preprocessJsonLogicRule(value, context, history, currentIndex);
|
|
68
90
|
}
|
|
69
91
|
return result;
|
|
70
92
|
}
|
|
71
93
|
// Primitive value, return as-is
|
|
72
94
|
return rule;
|
|
73
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate JSON Logic rule syntax without evaluating it
|
|
98
|
+
* Validates rule structure and any JSONata expressions in var operations
|
|
99
|
+
* @param rule - JSON Logic rule to validate
|
|
100
|
+
* @throws Error if syntax is invalid
|
|
101
|
+
*/
|
|
102
|
+
export function validateJsonLogicSyntax(rule) {
|
|
103
|
+
try {
|
|
104
|
+
validateJsonLogicRuleRecursive(rule);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (error instanceof Error) {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
throw new Error(`Invalid JSON Logic syntax: ${String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Recursively validate JSON Logic rule structure and JSONata in var operations
|
|
115
|
+
*/
|
|
116
|
+
function validateJsonLogicRuleRecursive(rule) {
|
|
117
|
+
// If rule is a var operation, validate the JSONata expression
|
|
118
|
+
if (typeof rule === "object" && rule !== null && "var" in rule && Object.keys(rule).length === 1) {
|
|
119
|
+
const path = rule.var;
|
|
120
|
+
if (typeof path !== "string") {
|
|
121
|
+
throw new Error(`JSON Logic var operation must have a string value, got ${typeof path}`);
|
|
122
|
+
}
|
|
123
|
+
// If the var value looks like a JSONata expression (starts with $), validate it
|
|
124
|
+
if (path.startsWith("$")) {
|
|
125
|
+
try {
|
|
126
|
+
validateJsonataSyntax(path);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error instanceof Error) {
|
|
130
|
+
throw new Error(`Invalid JSONata in JSON Logic var operation "${path}": ${error.message}`);
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// If it's not a JSONata expression, it's just a path reference (valid)
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// If rule is an array, recursively validate each element
|
|
139
|
+
if (Array.isArray(rule)) {
|
|
140
|
+
for (const item of rule) {
|
|
141
|
+
validateJsonLogicRuleRecursive(item);
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// If rule is an object, recursively validate each property
|
|
146
|
+
if (typeof rule === "object" && rule !== null) {
|
|
147
|
+
for (const value of Object.values(rule)) {
|
|
148
|
+
validateJsonLogicRuleRecursive(value);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Primitive values are valid
|
|
153
|
+
// Note: We can't fully validate JSON Logic operators without context,
|
|
154
|
+
// but we've validated the structure and any JSONata expressions
|
|
155
|
+
}
|
|
74
156
|
//# sourceMappingURL=json-logic.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-logic.js","sourceRoot":"","sources":["../../src/expressions/json-logic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2DAA2D;AAC3D,OAAO,SAAS,MAAM,eAAe,CAAC;AACtC,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC
|
|
1
|
+
{"version":3,"file":"json-logic.js","sourceRoot":"","sources":["../../src/expressions/json-logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONata extensions for execution history access
|
|
3
|
+
*/
|
|
4
|
+
import jsonata from "jsonata";
|
|
5
|
+
import type { NodeExecutionRecord } from "../types/execution.js";
|
|
6
|
+
/**
|
|
7
|
+
* Register custom JSONata functions for history access
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerHistoryFunctions(expr: jsonata.Expression, history: NodeExecutionRecord[], currentIndex: number): void;
|
|
10
|
+
//# sourceMappingURL=jsonata-extensions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonata-extensions.d.ts","sourceRoot":"","sources":["../../src/expressions/jsonata-extensions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,OAAO,CAAC,UAAU,EACxB,OAAO,EAAE,mBAAmB,EAAE,EAC9B,YAAY,EAAE,MAAM,GACnB,IAAI,CAiFN"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONata extensions for execution history access
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
/**
|
|
6
|
+
* Register custom JSONata functions for history access
|
|
7
|
+
*/
|
|
8
|
+
export function registerHistoryFunctions(expr, history, currentIndex) {
|
|
9
|
+
// $previousNode() - returns previous node's output
|
|
10
|
+
// $previousNode(index) - returns node that executed N steps before current
|
|
11
|
+
expr.registerFunction("previousNode", (offset) => {
|
|
12
|
+
const stepsBack = offset !== undefined ? offset : 1;
|
|
13
|
+
const targetIndex = currentIndex - stepsBack;
|
|
14
|
+
if (targetIndex < 0 || targetIndex >= history.length) {
|
|
15
|
+
logger.debug(`$previousNode(${stepsBack}): No node at index ${targetIndex}`);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const record = history[targetIndex];
|
|
19
|
+
logger.debug(`$previousNode(${stepsBack}) returning output from node: ${record.nodeId} (index ${targetIndex})`);
|
|
20
|
+
return record.output;
|
|
21
|
+
}, "<n?:o>" // Optional number argument, returns object
|
|
22
|
+
);
|
|
23
|
+
// $executionCount(nodeName) - count of executions for a node
|
|
24
|
+
expr.registerFunction("executionCount", (nodeName) => {
|
|
25
|
+
if (typeof nodeName !== "string") {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
const count = history.filter(r => r.nodeId === nodeName).length;
|
|
29
|
+
logger.debug(`$executionCount("${nodeName}") = ${count}`);
|
|
30
|
+
return count;
|
|
31
|
+
}, "<s:n>" // String argument, returns number
|
|
32
|
+
);
|
|
33
|
+
// $nodeExecution(nodeName, index) - specific execution by index (0 = first, -1 = last)
|
|
34
|
+
expr.registerFunction("nodeExecution", (nodeName, index) => {
|
|
35
|
+
if (typeof nodeName !== "string" || typeof index !== "number") {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const executions = history.filter(r => r.nodeId === nodeName);
|
|
39
|
+
if (executions.length === 0) {
|
|
40
|
+
logger.debug(`$nodeExecution("${nodeName}", ${index}): No executions found`);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Handle negative indices (from end)
|
|
44
|
+
let actualIndex = index;
|
|
45
|
+
if (index < 0) {
|
|
46
|
+
actualIndex = executions.length + index;
|
|
47
|
+
}
|
|
48
|
+
if (actualIndex < 0 || actualIndex >= executions.length) {
|
|
49
|
+
logger.debug(`$nodeExecution("${nodeName}", ${index}): Index ${actualIndex} out of range`);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const record = executions[actualIndex];
|
|
53
|
+
logger.debug(`$nodeExecution("${nodeName}", ${index}) = execution at index ${actualIndex}`);
|
|
54
|
+
return record.output;
|
|
55
|
+
}, "<s-n:o>" // String and number arguments, returns object
|
|
56
|
+
);
|
|
57
|
+
// $nodeExecutions(nodeName) - array of all executions for a node
|
|
58
|
+
expr.registerFunction("nodeExecutions", (nodeName) => {
|
|
59
|
+
if (typeof nodeName !== "string") {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
const executions = history.filter(r => r.nodeId === nodeName);
|
|
63
|
+
const outputs = executions.map(r => r.output);
|
|
64
|
+
logger.debug(`$nodeExecutions("${nodeName}") = ${executions.length} executions`);
|
|
65
|
+
return outputs;
|
|
66
|
+
}, "<s:a>" // String argument, returns array
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=jsonata-extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonata-extensions.js","sourceRoot":"","sources":["../../src/expressions/jsonata-extensions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JSONata expression evaluation
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
import type { NodeExecutionRecord } from "../types/execution.js";
|
|
5
|
+
/**
|
|
6
|
+
* Validate JSONata expression syntax without evaluating it
|
|
7
|
+
* @param expression - JSONata expression string to validate
|
|
8
|
+
* @throws Error if syntax is invalid
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateJsonataSyntax(expression: string): void;
|
|
11
|
+
export declare function evaluateJsonata(expression: string, context: Record<string, unknown>, history: NodeExecutionRecord[], currentIndex: number): Promise<unknown>;
|
|
5
12
|
//# sourceMappingURL=jsonata.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonata.d.ts","sourceRoot":"","sources":["../../src/expressions/jsonata.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"jsonata.d.ts","sourceRoot":"","sources":["../../src/expressions/jsonata.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CA2B9D;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,mBAAmB,EAAE,EAC9B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAqDlB"}
|
|
@@ -3,18 +3,48 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import jsonata from "jsonata";
|
|
5
5
|
import { logger } from "../logger.js";
|
|
6
|
-
|
|
6
|
+
import { registerHistoryFunctions } from "./jsonata-extensions.js";
|
|
7
|
+
/**
|
|
8
|
+
* Validate JSONata expression syntax without evaluating it
|
|
9
|
+
* @param expression - JSONata expression string to validate
|
|
10
|
+
* @throws Error if syntax is invalid
|
|
11
|
+
*/
|
|
12
|
+
export function validateJsonataSyntax(expression) {
|
|
7
13
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
jsonata(expression);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
// Extract detailed error message
|
|
18
|
+
let errorMessage;
|
|
19
|
+
if (error instanceof Error) {
|
|
20
|
+
errorMessage = error.message || error.toString();
|
|
21
|
+
if (errorMessage === '[object Object]' || !errorMessage) {
|
|
22
|
+
errorMessage = error.toString();
|
|
23
|
+
if (error.stack) {
|
|
24
|
+
errorMessage = error.stack.split('\n')[0] || errorMessage;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else if (error && typeof error === 'object') {
|
|
29
|
+
const errorObj = error;
|
|
30
|
+
if (errorObj.message && typeof errorObj.message === 'string') {
|
|
31
|
+
errorMessage = errorObj.message;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
errorMessage = JSON.stringify(error, null, 2);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
errorMessage = String(error);
|
|
17
39
|
}
|
|
40
|
+
throw new Error(`Invalid JSONata syntax: ${errorMessage}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export async function evaluateJsonata(expression, context, history, currentIndex) {
|
|
44
|
+
try {
|
|
45
|
+
const expr = jsonata(expression);
|
|
46
|
+
// Register history access functions
|
|
47
|
+
registerHistoryFunctions(expr, history, currentIndex);
|
|
18
48
|
const result = await expr.evaluate(context);
|
|
19
49
|
// Log for debugging
|
|
20
50
|
logger.debug(`JSONata expression: ${expression}`);
|
|
@@ -27,10 +57,40 @@ export async function evaluateJsonata(expression, context, previousNodeId) {
|
|
|
27
57
|
return result;
|
|
28
58
|
}
|
|
29
59
|
catch (error) {
|
|
30
|
-
|
|
60
|
+
// Extract detailed error message
|
|
61
|
+
let errorMessage;
|
|
62
|
+
if (error instanceof Error) {
|
|
63
|
+
errorMessage = error.message || error.toString();
|
|
64
|
+
// If message is still unhelpful, try to get more details
|
|
65
|
+
if (errorMessage === '[object Object]' || !errorMessage) {
|
|
66
|
+
errorMessage = error.toString();
|
|
67
|
+
// Try to get stack trace or other properties
|
|
68
|
+
if (error.stack) {
|
|
69
|
+
errorMessage = error.stack.split('\n')[0] || errorMessage;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (error && typeof error === 'object') {
|
|
74
|
+
// Try to extract meaningful information from error object
|
|
75
|
+
const errorObj = error;
|
|
76
|
+
if (errorObj.message && typeof errorObj.message === 'string') {
|
|
77
|
+
errorMessage = errorObj.message;
|
|
78
|
+
}
|
|
79
|
+
else if (errorObj.code && typeof errorObj.code === 'string') {
|
|
80
|
+
errorMessage = `Error code: ${errorObj.code}`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
errorMessage = JSON.stringify(error, null, 2);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
errorMessage = String(error);
|
|
88
|
+
}
|
|
89
|
+
logger.error(`JSONata evaluation error: ${errorMessage}`);
|
|
31
90
|
logger.error(`Expression: ${expression}`);
|
|
91
|
+
logger.error(`Context keys: ${Object.keys(context).join(', ')}`);
|
|
32
92
|
logger.error(`Context: ${JSON.stringify(context, null, 2)}`);
|
|
33
|
-
throw
|
|
93
|
+
throw new Error(`JSONata evaluation failed: ${errorMessage}\nExpression: ${expression}`);
|
|
34
94
|
}
|
|
35
95
|
}
|
|
36
96
|
//# sourceMappingURL=jsonata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonata.js","sourceRoot":"","sources":["../../src/expressions/jsonata.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"jsonata.js","sourceRoot":"","sources":["../../src/expressions/jsonata.ts"],"names":[],"mappings":"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"}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type definitions for mcpGraph configuration
|
|
3
3
|
*/
|
|
4
|
+
export interface ExecutionLimits {
|
|
5
|
+
maxNodeExecutions?: number;
|
|
6
|
+
maxExecutionTimeMs?: number;
|
|
7
|
+
}
|
|
4
8
|
export interface McpGraphConfig {
|
|
5
9
|
version: string;
|
|
6
10
|
server: ServerMetadata;
|
|
7
11
|
servers?: Record<string, ServerConfig>;
|
|
12
|
+
executionLimits?: ExecutionLimits;
|
|
8
13
|
tools: ToolDefinition[];
|
|
9
14
|
nodes: NodeDefinition[];
|
|
10
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/types/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,12 +5,12 @@ import type { NodeDefinition } from "./config.js";
|
|
|
5
5
|
import type { ExecutionContext } from "../execution/context.js";
|
|
6
6
|
export type ExecutionStatus = "not_started" | "running" | "paused" | "finished" | "error" | "stopped";
|
|
7
7
|
export interface NodeExecutionRecord {
|
|
8
|
+
executionIndex: number;
|
|
8
9
|
nodeId: string;
|
|
9
10
|
nodeType: string;
|
|
10
11
|
startTime: number;
|
|
11
12
|
endTime: number;
|
|
12
13
|
duration: number;
|
|
13
|
-
input: unknown;
|
|
14
14
|
output: unknown;
|
|
15
15
|
error?: Error;
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/types/execution.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAEtG,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../src/types/execution.ts"],"names":[],"mappings":"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"}
|
package/docs/design.md
CHANGED
|
@@ -124,17 +124,26 @@ Graph definitions should feel like Kubernetes manifests or GitHub Actions - decl
|
|
|
124
124
|
The YAML configuration centers around MCP server and tool definitions:
|
|
125
125
|
|
|
126
126
|
1. **MCP Server Metadata**: Defines the MCP server information (name, version, description)
|
|
127
|
-
2. **
|
|
127
|
+
2. **Execution Limits** (optional): Guardrails to prevent infinite loops in cyclical graphs:
|
|
128
|
+
- **`maxNodeExecutions`** (optional): Maximum total node executions across the entire graph. Default: `1000`. If execution reaches this limit, an error is thrown.
|
|
129
|
+
- **`maxExecutionTimeMs`** (optional): Maximum wall-clock time for graph execution in milliseconds. Default: `300000` (5 minutes). If execution exceeds this time, an error is thrown.
|
|
130
|
+
- Both limits are checked before each node execution. If either limit is exceeded, execution stops immediately with a clear error message.
|
|
131
|
+
3. **Tools**: Array of tool definitions, each containing:
|
|
128
132
|
- Standard MCP tool metadata (name, description)
|
|
129
133
|
- Input parameters schema (MCP tool parameter definitions)
|
|
130
134
|
- Output schema (what the tool returns)
|
|
131
135
|
- Note: Entry and exit nodes are defined in the nodes section with a `tool` field indicating which tool they belong to
|
|
132
|
-
|
|
136
|
+
4. **Nodes**: The directed graph of nodes that execute when tools are called. Node types include:
|
|
133
137
|
- **`entry`**: Entry point for a tool's graph execution. Receives tool arguments and initializes execution context.
|
|
138
|
+
- **Output**: The tool input arguments (passed through as-is)
|
|
134
139
|
- **`mcp`**: Calls an MCP tool on an internal or external MCP server using `callTool`
|
|
140
|
+
- **Output**: The MCP tool's response (parsed from the tool's content)
|
|
135
141
|
- **`transform`**: Applies JSONata expressions to transform data between nodes
|
|
142
|
+
- **Output**: The result of evaluating the JSONata expression
|
|
136
143
|
- **`switch`**: Uses JSON Logic to conditionally route to different nodes based on data
|
|
144
|
+
- **Output**: The node ID of the target node that was routed to (string)
|
|
137
145
|
- **`exit`**: Exit point for a tool's graph execution. Extracts and returns the final result to the MCP tool caller
|
|
146
|
+
- **Output**: The output from the previous node in the execution history
|
|
138
147
|
|
|
139
148
|
### Example YAML Structure: count_files Tool
|
|
140
149
|
|
|
@@ -149,6 +158,11 @@ server:
|
|
|
149
158
|
version: "1.0.0"
|
|
150
159
|
description: "File utilities"
|
|
151
160
|
|
|
161
|
+
# Optional: Execution limits to prevent infinite loops
|
|
162
|
+
executionLimits:
|
|
163
|
+
maxNodeExecutions: 1000 # Maximum total node executions (default: 1000)
|
|
164
|
+
maxExecutionTimeMs: 300000 # Maximum execution time in milliseconds (default: 300000 = 5 minutes)
|
|
165
|
+
|
|
152
166
|
# Tool Definitions
|
|
153
167
|
tools:
|
|
154
168
|
- name: "count_files"
|
|
@@ -223,5 +237,10 @@ nodes:
|
|
|
223
237
|
2. **Programmatic API**: Exports `McpGraphApi` class for programmatic use (e.g., by visualizer applications)
|
|
224
238
|
3. **Graph Executor**: Core orchestration engine that executes the directed graph sequentially
|
|
225
239
|
4. **Execution Context**: Tracks execution state, data flow, and history
|
|
240
|
+
- **Execution History**: Single source of truth - ordered array of all node executions with unique `executionIndex`
|
|
241
|
+
- **Context Building**: Context for expressions is built from history (most recent execution of each node wins)
|
|
242
|
+
- **Flat Structure**: Simple `{ "node_id": output }` structure - backward compatible with `$.node_id` notation
|
|
243
|
+
- **Loop Handling**: When nodes execute multiple times, context shows latest; history functions provide access to all executions
|
|
244
|
+
- **Time-Travel Debugging**: Can reconstruct context at any point in execution history
|
|
226
245
|
5. **Visual Editor**: Tools to visually view and edit the graph (future)
|
|
227
246
|
6. **Execution Observer**: Ability to observe and debug graph execution (future - see `docs/future-introspection-debugging.md`)
|
package/docs/implementation.md
CHANGED
|
@@ -33,6 +33,7 @@ The implementation creates a working MCP server that can:
|
|
|
33
33
|
All TypeScript interfaces defined:
|
|
34
34
|
- `McpGraphConfig` - Root configuration structure
|
|
35
35
|
- `ServerMetadata` - MCP server metadata
|
|
36
|
+
- `ExecutionLimits` - Optional execution limits configuration (maxNodeExecutions, maxExecutionTimeMs)
|
|
36
37
|
- `ToolDefinition` - Tool definition with input/output schemas (entry/exit nodes are defined in nodes with `tool` field)
|
|
37
38
|
- `NodeDefinition` - Base node interface
|
|
38
39
|
- `EntryNode` - Entry point node that receives tool arguments
|
|
@@ -212,11 +213,15 @@ Exit node execution:
|
|
|
212
213
|
**File: `src/execution/context.ts`**
|
|
213
214
|
|
|
214
215
|
Execution state management:
|
|
215
|
-
-
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
219
|
-
-
|
|
216
|
+
- **Execution History**: Single source of truth - ordered array of `NodeExecutionRecord` objects
|
|
217
|
+
- Each record includes: `executionIndex` (unique sequential ID), `nodeId`, `nodeType`, `startTime`, `endTime`, `duration`, `output`, `error`
|
|
218
|
+
- No `input` field - input context is derived from history when needed
|
|
219
|
+
- **Context Building**: Context for JSONata/JSON Logic is built from history once per node execution
|
|
220
|
+
- Walks backwards through history, most recent execution of each node wins
|
|
221
|
+
- Flat context structure: `{ "node_id": output, ... }` - backward compatible with `$.node_id` notation
|
|
222
|
+
- Supports time-travel debugging via `getContextForExecution(executionIndex)` - builds context up to a specific point
|
|
223
|
+
- **Data Access**: All data referenced by node ID (e.g., `$.entry_node_id.*`, `$.mcp_node_id.*`)
|
|
224
|
+
- **Loop Support**: When same node executes multiple times, context contains latest execution; history functions provide access to all executions
|
|
220
225
|
|
|
221
226
|
### 6.2 Graph Executor
|
|
222
227
|
|
|
@@ -231,7 +236,11 @@ Main graph execution orchestrator:
|
|
|
231
236
|
- Track execution history (node inputs/outputs)
|
|
232
237
|
- Handle errors with context
|
|
233
238
|
|
|
234
|
-
**Note:** The execution loop supports cycles (directed graphs with cycles)
|
|
239
|
+
**Note:** The execution loop supports cycles (directed graphs with cycles). To prevent infinite loops, execution limits are enforced:
|
|
240
|
+
- **`maxNodeExecutions`**: Maximum total node executions across the entire graph (default: 1000)
|
|
241
|
+
- **`maxExecutionTimeMs`**: Maximum wall-clock time for graph execution in milliseconds (default: 300000 = 5 minutes)
|
|
242
|
+
- Both limits are checked before each node execution. If either limit is exceeded, execution stops immediately with a clear error message.
|
|
243
|
+
- Limits are configurable in the YAML configuration via the optional `executionLimits` section.
|
|
235
244
|
|
|
236
245
|
### 6.3 Execution Flow
|
|
237
246
|
|
|
@@ -364,17 +364,19 @@ Execution history provides a complete record of all node executions with detaile
|
|
|
364
364
|
|
|
365
365
|
```typescript
|
|
366
366
|
interface NodeExecutionRecord {
|
|
367
|
+
executionIndex: number; // Position in overall execution history (0, 1, 2, ...) - unique identifier
|
|
367
368
|
nodeId: string; // ID of the executed node
|
|
368
369
|
nodeType: string; // Type of node (entry, exit, transform, mcp, switch)
|
|
369
370
|
startTime: number; // Timestamp when node started (milliseconds)
|
|
370
371
|
endTime: number; // Timestamp when node ended (milliseconds)
|
|
371
372
|
duration: number; // Execution duration (milliseconds)
|
|
372
|
-
input: unknown; // Input data for the node
|
|
373
373
|
output: unknown; // Output data from the node
|
|
374
374
|
error?: Error; // Error object if node failed
|
|
375
375
|
}
|
|
376
376
|
```
|
|
377
377
|
|
|
378
|
+
**Note**: The `input` field has been removed. Input context can be derived by building context from history up to the execution index using `getContextForExecution(executionIndex)`.
|
|
379
|
+
|
|
378
380
|
### Accessing History
|
|
379
381
|
|
|
380
382
|
```typescript
|
|
@@ -398,6 +400,31 @@ if (state) {
|
|
|
398
400
|
}
|
|
399
401
|
```
|
|
400
402
|
|
|
403
|
+
### Time-Travel Debugging
|
|
404
|
+
|
|
405
|
+
You can get the context that was available to a specific execution using `getContextForExecution()`:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
// Get context for a specific execution
|
|
409
|
+
const context = api.getContextForExecution(5);
|
|
410
|
+
if (context) {
|
|
411
|
+
console.log('Context available to execution #5:', context);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Get a specific execution record
|
|
415
|
+
const record = api.getExecutionByIndex(5);
|
|
416
|
+
if (record) {
|
|
417
|
+
console.log(`Execution #5: ${record.nodeId} executed at ${record.startTime}`);
|
|
418
|
+
console.log(`Output:`, record.output);
|
|
419
|
+
|
|
420
|
+
// Get the context that was available to this execution
|
|
421
|
+
const inputContext = api.getContextForExecution(record.executionIndex);
|
|
422
|
+
console.log('Input context:', inputContext);
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Note**: Both methods require an active execution with a controller (hooks/breakpoints enabled). They return `null` if no execution is in progress or the index is invalid.
|
|
427
|
+
|
|
401
428
|
## Telemetry
|
|
402
429
|
|
|
403
430
|
Telemetry provides aggregated performance metrics and execution statistics.
|