@o-lang/olang 1.0.14 → 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/package.json +1 -1
- package/src/runtime.js +47 -75
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
|
|
|
@@ -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
|
|