@o-lang/olang 1.0.3 → 1.0.4
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/cli.js +39 -4
- package/package.json +1 -1
- package/src/runtime.js +61 -3
package/cli.js
CHANGED
|
@@ -46,6 +46,34 @@ async function defaultMockResolver(action, context) {
|
|
|
46
46
|
return `[Unhandled: ${action}]`;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Built-in Math Resolver
|
|
51
|
+
* Supports minimal math operations for workflows
|
|
52
|
+
*/
|
|
53
|
+
async function builtInMathResolver(action, context) {
|
|
54
|
+
// Replace variables in context
|
|
55
|
+
action = action.replace(/\{([^\}]+)\}/g, (_, key) => {
|
|
56
|
+
const val = context[key.trim()];
|
|
57
|
+
return val !== undefined ? val : `{${key}}`;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
let match;
|
|
61
|
+
|
|
62
|
+
match = action.match(/^add\(([^,]+),\s*([^)]+)\)$/);
|
|
63
|
+
if (match) return parseFloat(match[1]) + parseFloat(match[2]);
|
|
64
|
+
|
|
65
|
+
match = action.match(/^subtract\(([^,]+),\s*([^)]+)\)$/);
|
|
66
|
+
if (match) return parseFloat(match[1]) - parseFloat(match[2]);
|
|
67
|
+
|
|
68
|
+
match = action.match(/^multiply\(([^,]+),\s*([^)]+)\)$/);
|
|
69
|
+
if (match) return parseFloat(match[1]) * parseFloat(match[2]);
|
|
70
|
+
|
|
71
|
+
match = action.match(/^divide\(([^,]+),\s*([^)]+)\)$/);
|
|
72
|
+
if (match) return parseFloat(match[1]) / parseFloat(match[2]);
|
|
73
|
+
|
|
74
|
+
return null; // not handled
|
|
75
|
+
}
|
|
76
|
+
|
|
49
77
|
/**
|
|
50
78
|
* Resolver chaining mechanism
|
|
51
79
|
*/
|
|
@@ -90,13 +118,20 @@ function loadSingleResolver(specifier) {
|
|
|
90
118
|
}
|
|
91
119
|
}
|
|
92
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Updated resolver chain
|
|
123
|
+
* Built-in math resolver is added first, then user resolvers, then default mock
|
|
124
|
+
*/
|
|
93
125
|
function loadResolverChain(specifiers) {
|
|
126
|
+
const userResolvers = specifiers?.map(loadSingleResolver) || [];
|
|
127
|
+
const resolvers = [builtInMathResolver, ...userResolvers, defaultMockResolver];
|
|
128
|
+
|
|
94
129
|
if (!specifiers || specifiers.length === 0) {
|
|
95
|
-
console.log('ℹ️ No resolver provided. Using default mock resolver.');
|
|
96
|
-
|
|
130
|
+
console.log('ℹ️ No resolver provided. Using built-in math + default mock resolver.');
|
|
131
|
+
} else {
|
|
132
|
+
console.log(`📦 Loaded user resolvers: ${specifiers.join(', ')}`);
|
|
97
133
|
}
|
|
98
134
|
|
|
99
|
-
const resolvers = specifiers.map(loadSingleResolver);
|
|
100
135
|
return createResolverChain(resolvers);
|
|
101
136
|
}
|
|
102
137
|
|
|
@@ -120,7 +155,7 @@ program
|
|
|
120
155
|
'Input parameters',
|
|
121
156
|
(val, acc = {}) => {
|
|
122
157
|
const [k, v] = val.split('=');
|
|
123
|
-
acc[k] = v;
|
|
158
|
+
acc[k] = isNaN(v) ? v : parseFloat(v);
|
|
124
159
|
return acc;
|
|
125
160
|
},
|
|
126
161
|
{}
|
package/package.json
CHANGED
package/src/runtime.js
CHANGED
|
@@ -24,9 +24,11 @@ class RuntimeAPI {
|
|
|
24
24
|
evaluateCondition(cond, ctx) {
|
|
25
25
|
cond = cond.trim();
|
|
26
26
|
const eq = cond.match(/^\{(.+)\}\s+equals\s+"(.*)"$/);
|
|
27
|
-
if (eq) return this.getNested(ctx, eq[1])
|
|
27
|
+
if (eq) return this.getNested(ctx, eq[1]) == eq[2];
|
|
28
28
|
const gt = cond.match(/^\{(.+)\}\s+greater than\s+(\d+\.?\d*)$/);
|
|
29
29
|
if (gt) return parseFloat(this.getNested(ctx, gt[1])) > parseFloat(gt[2]);
|
|
30
|
+
const lt = cond.match(/^\{(.+)\}\s+less than\s+(\d+\.?\d*)$/);
|
|
31
|
+
if (lt) return parseFloat(this.getNested(ctx, lt[1])) < parseFloat(lt[2]);
|
|
30
32
|
return Boolean(this.getNested(ctx, cond.replace(/\{|\}/g, '')));
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -45,8 +47,66 @@ class RuntimeAPI {
|
|
|
45
47
|
return null;
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
// --------------------------
|
|
51
|
+
// Math helper functions
|
|
52
|
+
// --------------------------
|
|
53
|
+
mathFunctions = {
|
|
54
|
+
add: (a, b) => a + b,
|
|
55
|
+
subtract: (a, b) => a - b,
|
|
56
|
+
multiply: (a, b) => a * b,
|
|
57
|
+
divide: (a, b) => a / b,
|
|
58
|
+
equals: (a, b) => a === b,
|
|
59
|
+
greater: (a, b) => a > b,
|
|
60
|
+
less: (a, b) => a < b,
|
|
61
|
+
sum: arr => arr.reduce((acc, val) => acc + val, 0),
|
|
62
|
+
avg: arr => arr.reduce((acc, val) => acc + val, 0) / arr.length,
|
|
63
|
+
min: arr => Math.min(...arr),
|
|
64
|
+
max: arr => Math.max(...arr),
|
|
65
|
+
increment: a => a + 1,
|
|
66
|
+
decrement: a => a - 1,
|
|
67
|
+
round: a => Math.round(a),
|
|
68
|
+
floor: a => Math.floor(a),
|
|
69
|
+
ceil: a => Math.ceil(a),
|
|
70
|
+
abs: a => Math.abs(a)
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
evaluateMath(expr) {
|
|
74
|
+
// Replace context variables in curly braces
|
|
75
|
+
expr = expr.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
76
|
+
const value = this.getNested(this.context, path.trim());
|
|
77
|
+
return value !== undefined ? value : 0;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Create a function for supported math functions only
|
|
81
|
+
const funcNames = Object.keys(this.mathFunctions);
|
|
82
|
+
const safeFunc = {};
|
|
83
|
+
funcNames.forEach(fn => {
|
|
84
|
+
safeFunc[fn] = this.mathFunctions[fn];
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
// eslint-disable-next-line no-new-func
|
|
89
|
+
const f = new Function(...funcNames, `return ${expr};`);
|
|
90
|
+
return f(...funcNames.map(fn => safeFunc[fn]));
|
|
91
|
+
} catch (e) {
|
|
92
|
+
console.warn(`[O-Lang] Failed to evaluate math expression "${expr}": ${e.message}`);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --------------------------
|
|
98
|
+
// Execute workflow step
|
|
99
|
+
// --------------------------
|
|
48
100
|
async executeStep(step, agentResolver) {
|
|
49
101
|
switch (step.type) {
|
|
102
|
+
case 'calculate': {
|
|
103
|
+
// e.g., "add({x}, {y})"
|
|
104
|
+
const expr = step.expression || step.actionRaw;
|
|
105
|
+
const result = this.evaluateMath(expr);
|
|
106
|
+
if (step.saveAs) this.context[step.saveAs] = result;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
|
|
50
110
|
case 'action': {
|
|
51
111
|
const action = step.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
52
112
|
const value = this.getNested(this.context, path.trim());
|
|
@@ -58,14 +118,12 @@ class RuntimeAPI {
|
|
|
58
118
|
}
|
|
59
119
|
|
|
60
120
|
case 'use': {
|
|
61
|
-
// "Use <Tool>" step
|
|
62
121
|
const res = await agentResolver(`Use ${step.tool}`, this.context);
|
|
63
122
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
64
123
|
break;
|
|
65
124
|
}
|
|
66
125
|
|
|
67
126
|
case 'ask': {
|
|
68
|
-
// "Ask <Target>" step
|
|
69
127
|
const res = await agentResolver(`Ask ${step.target}`, this.context);
|
|
70
128
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
71
129
|
break;
|