@o-lang/olang 1.0.13 → 1.0.15
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 +1 -1
- package/package.json +1 -1
- package/src/runtime.js +45 -76
package/cli.js
CHANGED
package/package.json
CHANGED
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
|
|
|
@@ -145,33 +145,36 @@ class RuntimeAPI {
|
|
|
145
145
|
const stepType = step.type;
|
|
146
146
|
|
|
147
147
|
const validateResolver = (resolver) => {
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
const resolverName = (resolver?.resolverName || resolver?.name || '').trim();
|
|
149
|
+
if (!resolverName) throw new Error('[O-Lang] Resolver missing name metadata');
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
const allowed = Array.from(this.allowedResolvers || []).map(r => r.trim());
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
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
|
+
};
|
|
155
158
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
this.allowedResolvers.add('builtInMathResolver');
|
|
159
|
-
allowed.push('builtInMathResolver');
|
|
160
|
-
}
|
|
159
|
+
const runResolvers = async (action) => {
|
|
160
|
+
const outputs = [];
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
throw new Error(`[O-Lang] Resolver "${resolverName}" is not allowed by workflow policy`);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
162
|
+
const mathPattern =
|
|
163
|
+
/^(Add|Subtract|Multiply|Divide|Sum|Avg|Min|Max|Round|Floor|Ceil|Abs)\b/i;
|
|
167
164
|
|
|
165
|
+
if (
|
|
166
|
+
step.actionRaw &&
|
|
167
|
+
mathPattern.test(step.actionRaw) &&
|
|
168
|
+
!this.allowedResolvers.has('builtInMathResolver')
|
|
169
|
+
) {
|
|
170
|
+
this.allowedResolvers.add('builtInMathResolver');
|
|
171
|
+
}
|
|
168
172
|
|
|
169
|
-
const runResolvers = async (action) => {
|
|
170
|
-
const outputs = [];
|
|
171
173
|
if (agentResolver && Array.isArray(agentResolver._chain)) {
|
|
172
174
|
for (let idx = 0; idx < agentResolver._chain.length; idx++) {
|
|
173
175
|
const resolver = agentResolver._chain[idx];
|
|
174
176
|
validateResolver(resolver);
|
|
177
|
+
|
|
175
178
|
try {
|
|
176
179
|
const out = await resolver(action, this.context);
|
|
177
180
|
outputs.push(out);
|
|
@@ -187,16 +190,17 @@ class RuntimeAPI {
|
|
|
187
190
|
outputs.push(out);
|
|
188
191
|
this.context['__resolver_0'] = out;
|
|
189
192
|
}
|
|
193
|
+
|
|
190
194
|
return outputs[outputs.length - 1];
|
|
191
195
|
};
|
|
192
196
|
|
|
193
|
-
// --- execute based on step.type ---
|
|
194
197
|
switch (stepType) {
|
|
195
198
|
case 'calculate': {
|
|
196
199
|
const result = this.evaluateMath(step.expression || step.actionRaw);
|
|
197
200
|
if (step.saveAs) this.context[step.saveAs] = result;
|
|
198
201
|
break;
|
|
199
202
|
}
|
|
203
|
+
|
|
200
204
|
case 'action': {
|
|
201
205
|
const action = step.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
202
206
|
const value = this.getNested(this.context, path.trim());
|
|
@@ -206,11 +210,10 @@ class RuntimeAPI {
|
|
|
206
210
|
const mathCall = action.match(/^(add|subtract|multiply|divide|sum|avg|min|max|round|floor|ceil|abs)\((.*)\)$/i);
|
|
207
211
|
if (mathCall) {
|
|
208
212
|
const fn = mathCall[1].toLowerCase();
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
if (/^".*"$/.test(s) || /^'.*'$/.test(s)) return s.slice(1, -1);
|
|
213
|
+
const args = mathCall[2].split(',').map(s => {
|
|
214
|
+
s = s.trim();
|
|
212
215
|
if (!isNaN(s)) return parseFloat(s);
|
|
213
|
-
return this.getNested(this.context, s.replace(/^\{|\}$/g, '')
|
|
216
|
+
return this.getNested(this.context, s.replace(/^\{|\}$/g, ''));
|
|
214
217
|
});
|
|
215
218
|
if (this.mathFunctions[fn]) {
|
|
216
219
|
const value = this.mathFunctions[fn](...args);
|
|
@@ -223,79 +226,45 @@ class RuntimeAPI {
|
|
|
223
226
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
224
227
|
break;
|
|
225
228
|
}
|
|
229
|
+
|
|
226
230
|
case 'use': {
|
|
227
231
|
const res = await runResolvers(`Use ${step.tool}`);
|
|
228
232
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
229
233
|
break;
|
|
230
234
|
}
|
|
235
|
+
|
|
231
236
|
case 'ask': {
|
|
232
237
|
const res = await runResolvers(`Ask ${step.target}`);
|
|
233
238
|
if (step.saveAs) this.context[step.saveAs] = res;
|
|
234
239
|
break;
|
|
235
240
|
}
|
|
241
|
+
|
|
236
242
|
case 'if': {
|
|
237
243
|
if (this.evaluateCondition(step.condition, this.context)) {
|
|
238
244
|
for (const s of step.body) await this.executeStep(s, agentResolver);
|
|
239
245
|
}
|
|
240
246
|
break;
|
|
241
247
|
}
|
|
248
|
+
|
|
242
249
|
case 'parallel': {
|
|
243
250
|
await Promise.all(step.steps.map(s => this.executeStep(s, agentResolver)));
|
|
244
251
|
break;
|
|
245
252
|
}
|
|
253
|
+
|
|
246
254
|
case 'connect': {
|
|
247
255
|
this.resources[step.resource] = step.endpoint;
|
|
248
256
|
break;
|
|
249
257
|
}
|
|
258
|
+
|
|
250
259
|
case 'agent_use': {
|
|
251
260
|
this.agentMap[step.logicalName] = step.resource;
|
|
252
261
|
break;
|
|
253
262
|
}
|
|
263
|
+
|
|
254
264
|
case 'debrief': {
|
|
255
265
|
this.emit('debrief', { agent: step.agent, message: step.message });
|
|
256
266
|
break;
|
|
257
267
|
}
|
|
258
|
-
case 'evolve': {
|
|
259
|
-
const maxGen = step.constraints?.max_generations || 1;
|
|
260
|
-
if (maxGen < 1) return;
|
|
261
|
-
const summaryStep = this.findLastSummaryStep();
|
|
262
|
-
if (!summaryStep) {
|
|
263
|
-
this.addWarning('Evolve step has no prior "Ask ... Save as" step to evolve');
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
const varName = summaryStep.saveAs;
|
|
267
|
-
let currentOutput = this.context[varName] || '';
|
|
268
|
-
for (let attempt = 0; attempt < maxGen; attempt++) {
|
|
269
|
-
let revisedAction = summaryStep.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
270
|
-
const val = this.getNested(this.context, path.trim());
|
|
271
|
-
return val !== undefined ? String(val) : `{${path}}`;
|
|
272
|
-
});
|
|
273
|
-
if (step.feedback) revisedAction += `\n[IMPROVEMENT FEEDBACK: ${step.feedback}]`;
|
|
274
|
-
currentOutput = await runResolvers(revisedAction);
|
|
275
|
-
this.context[varName] = currentOutput;
|
|
276
|
-
this.emit('debrief', {
|
|
277
|
-
agent: step.agent || 'Evolver',
|
|
278
|
-
message: `Evolve attempt ${attempt + 1}/${maxGen}: ${currentOutput.substring(0, 80)}...`
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
this.context['improved_summary'] = currentOutput;
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
case 'prompt': {
|
|
285
|
-
const input = await this.getUserInput(step.question);
|
|
286
|
-
if (step.saveAs) this.context[step.saveAs] = input;
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
case 'persist': {
|
|
290
|
-
const val = this.context[step.variable];
|
|
291
|
-
if (val !== undefined) fs.appendFileSync(step.target, JSON.stringify(val) + '\n', 'utf8');
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
case 'emit': {
|
|
295
|
-
const payload = step.payload ? this.getNested(this.context, step.payload) : undefined;
|
|
296
|
-
this.emit(step.event, payload || step.payload);
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
268
|
}
|
|
300
269
|
|
|
301
270
|
if (this.verbose) {
|
|
@@ -304,23 +273,23 @@ class RuntimeAPI {
|
|
|
304
273
|
}
|
|
305
274
|
}
|
|
306
275
|
|
|
307
|
-
async getUserInput(question) {
|
|
308
|
-
return new Promise(resolve => {
|
|
309
|
-
process.stdout.write(`${question}: `);
|
|
310
|
-
process.stdin.resume();
|
|
311
|
-
process.stdin.once('data', data => {
|
|
312
|
-
process.stdin.pause();
|
|
313
|
-
resolve(data.toString().trim());
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
276
|
async executeWorkflow(workflow, inputs, agentResolver) {
|
|
319
277
|
this.context = { ...inputs };
|
|
320
278
|
this.workflowSteps = workflow.steps;
|
|
321
279
|
this.allowedResolvers = new Set(workflow.allowedResolvers || []);
|
|
322
280
|
|
|
323
|
-
|
|
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
|
+
}
|
|
324
293
|
|
|
325
294
|
this.printDisallowedSummary();
|
|
326
295
|
|