@o-lang/olang 1.0.14 → 1.0.16
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/package.json +1 -1
- package/src/parser.js +72 -93
- package/src/runtime.js +47 -75
package/package.json
CHANGED
package/src/parser.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
// src/parser.js
|
|
2
|
-
|
|
3
2
|
function parse(code, fileName = null) {
|
|
4
3
|
if (fileName && !fileName.endsWith(".ol")) {
|
|
5
4
|
throw new Error(`Expected .ol workflow, got: ${fileName}`);
|
|
6
5
|
}
|
|
7
|
-
|
|
8
6
|
const rawLines = code.split(/\r?\n/);
|
|
9
|
-
|
|
10
7
|
const lines = rawLines
|
|
11
8
|
.map(l => l.trim())
|
|
12
9
|
.filter(l => l && !l.startsWith('#') && !l.startsWith('//'));
|
|
@@ -17,37 +14,41 @@ function parse(code, fileName = null) {
|
|
|
17
14
|
steps: [],
|
|
18
15
|
returnValues: [],
|
|
19
16
|
allowedResolvers: [],
|
|
20
|
-
|
|
21
17
|
resolverPolicy: {
|
|
22
18
|
declared: [],
|
|
23
19
|
autoInjected: [],
|
|
24
20
|
used: [],
|
|
25
21
|
warnings: []
|
|
26
22
|
},
|
|
27
|
-
|
|
28
23
|
__warnings: [],
|
|
29
24
|
__requiresMath: false
|
|
30
25
|
};
|
|
31
26
|
|
|
32
27
|
let i = 0;
|
|
33
|
-
|
|
34
28
|
while (i < lines.length) {
|
|
35
29
|
let line = lines[i];
|
|
36
30
|
|
|
37
|
-
|
|
31
|
+
// ✅ FIXED: Match both "Allow resolvers" and "Allowed resolvers"
|
|
32
|
+
const allowMatch = line.match(/^Allow(?:ed)?\s+resolvers\s*:\s*$/i);
|
|
38
33
|
if (allowMatch) {
|
|
39
34
|
i++;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
// Read all subsequent non-empty lines until a new top-level section (starts with capital letter)
|
|
36
|
+
while (i < lines.length) {
|
|
37
|
+
const nextLine = lines[i].trim();
|
|
38
|
+
// Stop if line is empty or appears to be a new top-level keyword (e.g., Step, Workflow, Return)
|
|
39
|
+
if (nextLine === '' || /^[A-Z][a-z]/.test(nextLine)) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
if (nextLine) {
|
|
43
|
+
workflow.allowedResolvers.push(nextLine);
|
|
44
|
+
workflow.resolverPolicy.declared.push(nextLine);
|
|
45
45
|
}
|
|
46
46
|
i++;
|
|
47
47
|
}
|
|
48
48
|
continue;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
// ---- Math step patterns (standalone) ----
|
|
51
52
|
let mathAdd = line.match(/^Add\s+\{(.+?)\}\s+and\s+\{(.+?)\}\s+Save as\s+(.+)$/i);
|
|
52
53
|
if (mathAdd) {
|
|
53
54
|
workflow.__requiresMath = true;
|
|
@@ -65,7 +66,7 @@ function parse(code, fileName = null) {
|
|
|
65
66
|
workflow.__requiresMath = true;
|
|
66
67
|
workflow.steps.push({
|
|
67
68
|
type: 'calculate',
|
|
68
|
-
expression: `subtract({${
|
|
69
|
+
expression: `subtract({${mathAdd[2]}}, {${mathAdd[1]}})`,
|
|
69
70
|
saveAs: mathSub[3].trim()
|
|
70
71
|
});
|
|
71
72
|
i++;
|
|
@@ -96,6 +97,7 @@ function parse(code, fileName = null) {
|
|
|
96
97
|
continue;
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
// ---- Workflow declaration ----
|
|
99
101
|
const wfMatch = line.match(/^Workflow\s+"([^"]+)"(?:\s+with\s+(.+))?/i);
|
|
100
102
|
if (wfMatch) {
|
|
101
103
|
workflow.name = wfMatch[1];
|
|
@@ -106,96 +108,84 @@ function parse(code, fileName = null) {
|
|
|
106
108
|
continue;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
i++;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// ---------------------------
|
|
131
|
-
// Steps (updated: auto-detect math + saveAs)
|
|
132
|
-
// ---------------------------
|
|
133
|
-
const stepMatch = line.match(/^Step\s+(\d+)\s*:\s*(.+)$/i);
|
|
134
|
-
if (stepMatch) {
|
|
135
|
-
const stepNum = parseInt(stepMatch[1], 10);
|
|
136
|
-
const raw = stepMatch[2].trim();
|
|
137
|
-
|
|
138
|
-
// --- Detect math inside Step ---
|
|
139
|
-
let mathDetected = null;
|
|
140
|
-
let expr = '';
|
|
141
|
-
let saveVar = null;
|
|
142
|
-
|
|
143
|
-
const mathOps = [
|
|
144
|
-
{ re: /^Add\s+\{(.+?)\}\s+and\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'add' },
|
|
145
|
-
{ re: /^Subtract\s+\{(.+?)\}\s+from\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'subtract' },
|
|
146
|
-
{ re: /^Multiply\s+\{(.+?)\}\s+and\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'multiply' },
|
|
147
|
-
{ re: /^Divide\s+\{(.+?)\}\s+by\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'divide' }
|
|
148
|
-
];
|
|
149
|
-
|
|
150
|
-
for (const op of mathOps) {
|
|
151
|
-
const m = raw.match(op.re);
|
|
152
|
-
if (m) {
|
|
153
|
-
mathDetected = op.fn;
|
|
154
|
-
saveVar = m[3].trim();
|
|
155
|
-
if (op.fn === 'subtract') expr = `subtract({${m[2]}}, {${m[1]}})`;
|
|
156
|
-
else expr = `${op.fn}({${m[1]}}, {${m[2]}})`;
|
|
157
|
-
break;
|
|
111
|
+
// ---- Return statement (updated: auto-detect math) ----
|
|
112
|
+
const returnMatch = line.match(/^Return\s+(.+)$/i);
|
|
113
|
+
if (returnMatch) {
|
|
114
|
+
const returns = returnMatch[1].split(',').map(v => v.trim());
|
|
115
|
+
workflow.returnValues = returns;
|
|
116
|
+
// Check if any return vars come from math steps
|
|
117
|
+
for (const retVar of returns) {
|
|
118
|
+
const producedByMath = workflow.steps.some(
|
|
119
|
+
s => s.saveAs === retVar && s.type === 'calculate'
|
|
120
|
+
);
|
|
121
|
+
if (producedByMath) workflow.__requiresMath = true;
|
|
122
|
+
}
|
|
123
|
+
i++;
|
|
124
|
+
continue;
|
|
158
125
|
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (mathDetected) workflow.__requiresMath = true;
|
|
162
|
-
|
|
163
|
-
workflow.steps.push({
|
|
164
|
-
type: mathDetected ? 'calculate' : 'action',
|
|
165
|
-
stepNumber: stepNum,
|
|
166
|
-
actionRaw: mathDetected ? null : raw,
|
|
167
|
-
expression: mathDetected ? expr : undefined,
|
|
168
|
-
saveAs: saveVar,
|
|
169
|
-
constraints: {}
|
|
170
|
-
});
|
|
171
126
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
127
|
+
// ---- Step parsing (with inline math detection) ----
|
|
128
|
+
const stepMatch = line.match(/^Step\s+(\d+)\s*:\s*(.+)$/i);
|
|
129
|
+
if (stepMatch) {
|
|
130
|
+
const stepNum = parseInt(stepMatch[1], 10);
|
|
131
|
+
const raw = stepMatch[2].trim();
|
|
132
|
+
|
|
133
|
+
let mathDetected = null;
|
|
134
|
+
let expr = '';
|
|
135
|
+
let saveVar = null;
|
|
136
|
+
const mathOps = [
|
|
137
|
+
{ re: /^Add\s+\{(.+?)\}\s+and\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'add' },
|
|
138
|
+
{ re: /^Subtract\s+\{(.+?)\}\s+from\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'subtract' },
|
|
139
|
+
{ re: /^Multiply\s+\{(.+?)\}\s+and\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'multiply' },
|
|
140
|
+
{ re: /^Divide\s+\{(.+?)\}\s+by\s+\{(.+?)\}\s+Save as\s+(.+)$/i, fn: 'divide' }
|
|
141
|
+
];
|
|
142
|
+
for (const op of mathOps) {
|
|
143
|
+
const m = raw.match(op.re);
|
|
144
|
+
if (m) {
|
|
145
|
+
mathDetected = op.fn;
|
|
146
|
+
saveVar = m[3].trim();
|
|
147
|
+
if (op.fn === 'subtract') {
|
|
148
|
+
expr = `subtract({${m[2]}}, {${m[1]}})`;
|
|
149
|
+
} else {
|
|
150
|
+
expr = `${op.fn}({${m[1]}}, {${m[2]}})`;
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (mathDetected) workflow.__requiresMath = true;
|
|
156
|
+
workflow.steps.push({
|
|
157
|
+
type: mathDetected ? 'calculate' : 'action',
|
|
158
|
+
stepNumber: stepNum,
|
|
159
|
+
actionRaw: mathDetected ? null : raw,
|
|
160
|
+
expression: mathDetected ? expr : undefined,
|
|
161
|
+
saveAs: saveVar,
|
|
162
|
+
constraints: {}
|
|
163
|
+
});
|
|
164
|
+
i++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
175
167
|
|
|
168
|
+
// ---- Save as (for legacy or multi-line steps) ----
|
|
176
169
|
const saveMatch = line.match(/^Save as\s+(.+)$/i);
|
|
177
170
|
if (saveMatch && workflow.steps.length > 0) {
|
|
178
171
|
const lastStep = workflow.steps[workflow.steps.length - 1];
|
|
179
172
|
lastStep.saveAs = saveMatch[1].trim();
|
|
180
|
-
|
|
181
173
|
if (lastStep.saveAs.match(/[A-Z][A-Za-z0-9_]*/)) {
|
|
182
174
|
workflow.__requiresMath = true;
|
|
183
175
|
}
|
|
184
|
-
|
|
185
176
|
i++;
|
|
186
177
|
continue;
|
|
187
178
|
}
|
|
188
179
|
|
|
180
|
+
// ---- Constraint parsing ----
|
|
189
181
|
const constraintMatch = line.match(/^Constraint:\s*(.+)$/i);
|
|
190
182
|
if (constraintMatch && workflow.steps.length > 0) {
|
|
191
183
|
const lastStep = workflow.steps[workflow.steps.length - 1];
|
|
192
184
|
if (!lastStep.constraints) lastStep.constraints = {};
|
|
193
|
-
|
|
194
185
|
const eq = constraintMatch[1].match(/^([^=]+)=\s*(.+)$/);
|
|
195
186
|
if (eq) {
|
|
196
187
|
let key = eq[1].trim();
|
|
197
188
|
let value = eq[2].trim();
|
|
198
|
-
|
|
199
189
|
if (value.startsWith('[') && value.endsWith(']')) {
|
|
200
190
|
value = value.slice(1, -1).split(',').map(v =>
|
|
201
191
|
v.trim().replace(/^"/, '').replace(/"$/, '')
|
|
@@ -205,7 +195,6 @@ if (stepMatch) {
|
|
|
205
195
|
} else if (value.startsWith('"') && value.endsWith('"')) {
|
|
206
196
|
value = value.slice(1, -1);
|
|
207
197
|
}
|
|
208
|
-
|
|
209
198
|
lastStep.constraints[key] = value;
|
|
210
199
|
}
|
|
211
200
|
i++;
|
|
@@ -220,7 +209,6 @@ if (stepMatch) {
|
|
|
220
209
|
// ============================
|
|
221
210
|
if (workflow.__requiresMath) {
|
|
222
211
|
workflow.resolverPolicy.used.push('builtInMathResolver');
|
|
223
|
-
|
|
224
212
|
if (!workflow.resolverPolicy.declared.includes('builtInMathResolver')) {
|
|
225
213
|
workflow.resolverPolicy.autoInjected.push('builtInMathResolver');
|
|
226
214
|
workflow.allowedResolvers.unshift('builtInMathResolver');
|
|
@@ -237,7 +225,6 @@ if (stepMatch) {
|
|
|
237
225
|
}
|
|
238
226
|
|
|
239
227
|
workflow.resolverPolicy.warnings = workflow.__warnings.slice();
|
|
240
|
-
|
|
241
228
|
return workflow;
|
|
242
229
|
}
|
|
243
230
|
|
|
@@ -247,7 +234,6 @@ if (stepMatch) {
|
|
|
247
234
|
function parseBlock(lines) {
|
|
248
235
|
const steps = [];
|
|
249
236
|
let current = null;
|
|
250
|
-
|
|
251
237
|
for (const line of lines) {
|
|
252
238
|
const stepMatch = line.match(/^Step\s+(\d+)\s*:\s*(.+)$/i);
|
|
253
239
|
if (stepMatch) {
|
|
@@ -261,37 +247,30 @@ function parseBlock(lines) {
|
|
|
261
247
|
steps.push(current);
|
|
262
248
|
continue;
|
|
263
249
|
}
|
|
264
|
-
|
|
265
250
|
const saveMatch = line.match(/^Save as\s+(.+)$/i);
|
|
266
251
|
if (saveMatch && current) current.saveAs = saveMatch[1].trim();
|
|
267
|
-
|
|
268
252
|
const debriefMatch = line.match(/^Debrief\s+(\w+)\s+with\s+"(.+)"$/i);
|
|
269
253
|
if (debriefMatch) {
|
|
270
254
|
steps.push({ type: 'debrief', agent: debriefMatch[1], message: debriefMatch[2] });
|
|
271
255
|
}
|
|
272
|
-
|
|
273
256
|
const evolveMatch = line.match(/^Evolve\s+(\w+)\s+using\s+feedback:\s+"(.+)"$/i);
|
|
274
257
|
if (evolveMatch) {
|
|
275
258
|
steps.push({ type: 'evolve', agent: evolveMatch[1], feedback: evolveMatch[2] });
|
|
276
259
|
}
|
|
277
|
-
|
|
278
260
|
const promptMatch = line.match(/^Prompt user to\s+"(.+)"$/i);
|
|
279
261
|
if (promptMatch) {
|
|
280
262
|
steps.push({ type: 'prompt', question: promptMatch[1], saveAs: null });
|
|
281
263
|
}
|
|
282
|
-
|
|
283
264
|
const useMatch = line.match(/^Use\s+(.+)$/i);
|
|
284
265
|
if (useMatch) {
|
|
285
266
|
steps.push({ type: 'use', tool: useMatch[1].trim(), saveAs: null, constraints: {} });
|
|
286
267
|
}
|
|
287
|
-
|
|
288
268
|
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
289
269
|
if (askMatch) {
|
|
290
270
|
steps.push({ type: 'ask', target: askMatch[1].trim(), saveAs: null, constraints: {} });
|
|
291
271
|
}
|
|
292
272
|
}
|
|
293
|
-
|
|
294
273
|
return steps;
|
|
295
274
|
}
|
|
296
275
|
|
|
297
|
-
module.exports = { parse };
|
|
276
|
+
module.exports = { parse };
|
package/src/runtime.js
CHANGED
|
@@ -86,7 +86,7 @@ class RuntimeAPI {
|
|
|
86
86
|
const gt = cond.match(/^\{(.+)\}\s+greater than\s+(\d+\.?\d*)$/);
|
|
87
87
|
if (gt) return parseFloat(this.getNested(ctx, gt[1])) > parseFloat(gt[2]);
|
|
88
88
|
const lt = cond.match(/^\{(.+)\}\s+less than\s+(\d+\.?\d*)$/);
|
|
89
|
-
if (lt) return parseFloat(this.getNested(ctx, lt[1])) < parseFloat(
|
|
89
|
+
if (lt) return parseFloat(this.getNested(ctx, lt[1])) < parseFloat(gt[2]);
|
|
90
90
|
return Boolean(this.getNested(ctx, cond.replace(/\{|\}/g, '')));
|
|
91
91
|
}
|
|
92
92
|
|
|
@@ -144,31 +144,37 @@ class RuntimeAPI {
|
|
|
144
144
|
async executeStep(step, agentResolver) {
|
|
145
145
|
const stepType = step.type;
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
const validateResolver = (resolver) => {
|
|
148
|
+
const resolverName = (resolver?.resolverName || resolver?.name || '').trim();
|
|
149
|
+
if (!resolverName) throw new Error('[O-Lang] Resolver missing name metadata');
|
|
150
150
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// Auto-inject builtInMathResolver if step type is 'calculate' and resolver is math
|
|
154
|
-
if (step.type === 'calculate' && resolverName === 'builtInMathResolver' && !allowed.includes('builtInMathResolver')) {
|
|
155
|
-
this.allowedResolvers.add('builtInMathResolver');
|
|
156
|
-
allowed.push('builtInMathResolver');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (!allowed.includes(resolverName)) {
|
|
160
|
-
this.logDisallowedResolver(resolverName, step.actionRaw || step.tool || step.target);
|
|
161
|
-
throw new Error(`[O-Lang] Resolver "${resolverName}" is not allowed by workflow policy`);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
151
|
+
const allowed = Array.from(this.allowedResolvers || []).map(r => r.trim());
|
|
164
152
|
|
|
153
|
+
if (!allowed.includes(resolverName)) {
|
|
154
|
+
this.logDisallowedResolver(resolverName, step.actionRaw || step.tool || step.target);
|
|
155
|
+
throw new Error(`[O-Lang] Resolver "${resolverName}" is not allowed by workflow policy`);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
165
158
|
|
|
166
159
|
const runResolvers = async (action) => {
|
|
167
160
|
const outputs = [];
|
|
161
|
+
|
|
162
|
+
const mathPattern =
|
|
163
|
+
/^(Add|Subtract|Multiply|Divide|Sum|Avg|Min|Max|Round|Floor|Ceil|Abs)\b/i;
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
step.actionRaw &&
|
|
167
|
+
mathPattern.test(step.actionRaw) &&
|
|
168
|
+
!this.allowedResolvers.has('builtInMathResolver')
|
|
169
|
+
) {
|
|
170
|
+
this.allowedResolvers.add('builtInMathResolver');
|
|
171
|
+
}
|
|
172
|
+
|
|
168
173
|
if (agentResolver && Array.isArray(agentResolver._chain)) {
|
|
169
174
|
for (let idx = 0; idx < agentResolver._chain.length; idx++) {
|
|
170
175
|
const resolver = agentResolver._chain[idx];
|
|
171
176
|
validateResolver(resolver);
|
|
177
|
+
|
|
172
178
|
try {
|
|
173
179
|
const out = await resolver(action, this.context);
|
|
174
180
|
outputs.push(out);
|
|
@@ -184,16 +190,17 @@ class RuntimeAPI {
|
|
|
184
190
|
outputs.push(out);
|
|
185
191
|
this.context['__resolver_0'] = out;
|
|
186
192
|
}
|
|
193
|
+
|
|
187
194
|
return outputs[outputs.length - 1];
|
|
188
195
|
};
|
|
189
196
|
|
|
190
|
-
// --- execute based on step.type ---
|
|
191
197
|
switch (stepType) {
|
|
192
198
|
case 'calculate': {
|
|
193
199
|
const result = this.evaluateMath(step.expression || step.actionRaw);
|
|
194
200
|
if (step.saveAs) this.context[step.saveAs] = result;
|
|
195
201
|
break;
|
|
196
202
|
}
|
|
203
|
+
|
|
197
204
|
case 'action': {
|
|
198
205
|
const action = step.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
199
206
|
const value = this.getNested(this.context, path.trim());
|
|
@@ -203,11 +210,10 @@ class RuntimeAPI {
|
|
|
203
210
|
const mathCall = action.match(/^(add|subtract|multiply|divide|sum|avg|min|max|round|floor|ceil|abs)\((.*)\)$/i);
|
|
204
211
|
if (mathCall) {
|
|
205
212
|
const fn = mathCall[1].toLowerCase();
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
if (/^".*"$/.test(s) || /^'.*'$/.test(s)) return s.slice(1, -1);
|
|
213
|
+
const args = mathCall[2].split(',').map(s => {
|
|
214
|
+
s = s.trim();
|
|
209
215
|
if (!isNaN(s)) return parseFloat(s);
|
|
210
|
-
return this.getNested(this.context, s.replace(/^\{|\}$/g, '')
|
|
216
|
+
return this.getNested(this.context, s.replace(/^\{|\}$/g, ''));
|
|
211
217
|
});
|
|
212
218
|
if (this.mathFunctions[fn]) {
|
|
213
219
|
const value = this.mathFunctions[fn](...args);
|
|
@@ -220,79 +226,45 @@ class RuntimeAPI {
|
|
|
220
226
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
221
227
|
break;
|
|
222
228
|
}
|
|
229
|
+
|
|
223
230
|
case 'use': {
|
|
224
231
|
const res = await runResolvers(`Use ${step.tool}`);
|
|
225
232
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
226
233
|
break;
|
|
227
234
|
}
|
|
235
|
+
|
|
228
236
|
case 'ask': {
|
|
229
237
|
const res = await runResolvers(`Ask ${step.target}`);
|
|
230
238
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
231
239
|
break;
|
|
232
240
|
}
|
|
241
|
+
|
|
233
242
|
case 'if': {
|
|
234
243
|
if (this.evaluateCondition(step.condition, this.context)) {
|
|
235
244
|
for (const s of step.body) await this.executeStep(s, agentResolver);
|
|
236
245
|
}
|
|
237
246
|
break;
|
|
238
247
|
}
|
|
248
|
+
|
|
239
249
|
case 'parallel': {
|
|
240
250
|
await Promise.all(step.steps.map(s => this.executeStep(s, agentResolver)));
|
|
241
251
|
break;
|
|
242
252
|
}
|
|
253
|
+
|
|
243
254
|
case 'connect': {
|
|
244
255
|
this.resources[step.resource] = step.endpoint;
|
|
245
256
|
break;
|
|
246
257
|
}
|
|
258
|
+
|
|
247
259
|
case 'agent_use': {
|
|
248
260
|
this.agentMap[step.logicalName] = step.resource;
|
|
249
261
|
break;
|
|
250
262
|
}
|
|
263
|
+
|
|
251
264
|
case 'debrief': {
|
|
252
265
|
this.emit('debrief', { agent: step.agent, message: step.message });
|
|
253
266
|
break;
|
|
254
267
|
}
|
|
255
|
-
case 'evolve': {
|
|
256
|
-
const maxGen = step.constraints?.max_generations || 1;
|
|
257
|
-
if (maxGen < 1) return;
|
|
258
|
-
const summaryStep = this.findLastSummaryStep();
|
|
259
|
-
if (!summaryStep) {
|
|
260
|
-
this.addWarning('Evolve step has no prior "Ask ... Save as" step to evolve');
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const varName = summaryStep.saveAs;
|
|
264
|
-
let currentOutput = this.context[varName] || '';
|
|
265
|
-
for (let attempt = 0; attempt < maxGen; attempt++) {
|
|
266
|
-
let revisedAction = summaryStep.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
267
|
-
const val = this.getNested(this.context, path.trim());
|
|
268
|
-
return val !== undefined ? String(val) : `{${path}}`;
|
|
269
|
-
});
|
|
270
|
-
if (step.feedback) revisedAction += `\n[IMPROVEMENT FEEDBACK: ${step.feedback}]`;
|
|
271
|
-
currentOutput = await runResolvers(revisedAction);
|
|
272
|
-
this.context[varName] = currentOutput;
|
|
273
|
-
this.emit('debrief', {
|
|
274
|
-
agent: step.agent || 'Evolver',
|
|
275
|
-
message: `Evolve attempt ${attempt + 1}/${maxGen}: ${currentOutput.substring(0, 80)}...`
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
this.context['improved_summary'] = currentOutput;
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
case 'prompt': {
|
|
282
|
-
const input = await this.getUserInput(step.question);
|
|
283
|
-
if (step.saveAs) this.context[step.saveAs] = input;
|
|
284
|
-
break;
|
|
285
|
-
}
|
|
286
|
-
case 'persist': {
|
|
287
|
-
const val = this.context[step.variable];
|
|
288
|
-
if (val !== undefined) fs.appendFileSync(step.target, JSON.stringify(val) + '\n', 'utf8');
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
291
|
-
case 'emit': {
|
|
292
|
-
const payload = step.payload ? this.getNested(this.context, step.payload) : undefined;
|
|
293
|
-
this.emit(step.event, payload || step.payload);
|
|
294
|
-
break;
|
|
295
|
-
}
|
|
296
268
|
}
|
|
297
269
|
|
|
298
270
|
if (this.verbose) {
|
|
@@ -301,23 +273,23 @@ class RuntimeAPI {
|
|
|
301
273
|
}
|
|
302
274
|
}
|
|
303
275
|
|
|
304
|
-
async getUserInput(question) {
|
|
305
|
-
return new Promise(resolve => {
|
|
306
|
-
process.stdout.write(`${question}: `);
|
|
307
|
-
process.stdin.resume();
|
|
308
|
-
process.stdin.once('data', data => {
|
|
309
|
-
process.stdin.pause();
|
|
310
|
-
resolve(data.toString().trim());
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
|
|
315
276
|
async executeWorkflow(workflow, inputs, agentResolver) {
|
|
316
277
|
this.context = { ...inputs };
|
|
317
278
|
this.workflowSteps = workflow.steps;
|
|
318
279
|
this.allowedResolvers = new Set(workflow.allowedResolvers || []);
|
|
319
280
|
|
|
320
|
-
|
|
281
|
+
const mathPattern =
|
|
282
|
+
/^(Add|Subtract|Multiply|Divide|Sum|Avg|Min|Max|Round|Floor|Ceil|Abs)\b/i;
|
|
283
|
+
|
|
284
|
+
for (const step of workflow.steps) {
|
|
285
|
+
if (step.type === 'calculate' || (step.actionRaw && mathPattern.test(step.actionRaw))) {
|
|
286
|
+
this.allowedResolvers.add('builtInMathResolver');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
for (const step of workflow.steps) {
|
|
291
|
+
await this.executeStep(step, agentResolver);
|
|
292
|
+
}
|
|
321
293
|
|
|
322
294
|
this.printDisallowedSummary();
|
|
323
295
|
|