@o-lang/olang 1.0.0 â 1.0.2
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 +0 -76
- package/package.json +16 -5
- package/src/parser.js +45 -221
- package/src/runtime.js +18 -136
package/cli.js
CHANGED
|
@@ -113,79 +113,3 @@ program.parse(process.argv);
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// #!/usr/bin/env node
|
|
119
|
-
// const { Command } = require('commander');
|
|
120
|
-
// const { parse } = require('./src/parser');
|
|
121
|
-
// const { execute } = require('./src/runtime');
|
|
122
|
-
// const fs = require('fs');
|
|
123
|
-
// const path = require('path');
|
|
124
|
-
|
|
125
|
-
// // Default mock resolver (for demos)
|
|
126
|
-
// async function defaultMockResolver(action, context) {
|
|
127
|
-
// if (action.startsWith('Search for ')) {
|
|
128
|
-
// return {
|
|
129
|
-
// title: "HR Policy 2025",
|
|
130
|
-
// text: "Employees are entitled to 20 days of paid leave per year. All requests must be submitted via the HR portal.",
|
|
131
|
-
// url: "mock://hr-policy"
|
|
132
|
-
// };
|
|
133
|
-
// }
|
|
134
|
-
// if (action.startsWith('Ask ')) {
|
|
135
|
-
// return "â
[Mock] Summarized for staff.";
|
|
136
|
-
// }
|
|
137
|
-
// if (action.startsWith('Notify ')) {
|
|
138
|
-
// const recipient = action.match(/Notify (\S+)/)?.[1] || 'user@example.com';
|
|
139
|
-
// return `đŦ Notification sent to ${recipient}`;
|
|
140
|
-
// }
|
|
141
|
-
// if (action.startsWith('Debrief ') || action.startsWith('Evolve ')) {
|
|
142
|
-
// console.log(`[O-Lang] ${action}`);
|
|
143
|
-
// return 'Acknowledged';
|
|
144
|
-
// }
|
|
145
|
-
// return `[Unhandled: ${action}]`;
|
|
146
|
-
// }
|
|
147
|
-
|
|
148
|
-
// function loadResolver(resolverPath) {
|
|
149
|
-
// if (!resolverPath) {
|
|
150
|
-
// console.log('âšī¸ No resolver provided. Using default mock resolver.');
|
|
151
|
-
// return defaultMockResolver;
|
|
152
|
-
// }
|
|
153
|
-
|
|
154
|
-
// try {
|
|
155
|
-
// // Resolve relative to current working directory
|
|
156
|
-
// const absolutePath = path.resolve(process.cwd(), resolverPath);
|
|
157
|
-
// return require(absolutePath);
|
|
158
|
-
// } catch (err) {
|
|
159
|
-
// console.error(`â Failed to load resolver from: ${resolverPath}`);
|
|
160
|
-
// console.error(`Error: ${err.message}`);
|
|
161
|
-
// process.exit(1);
|
|
162
|
-
// }
|
|
163
|
-
// }
|
|
164
|
-
|
|
165
|
-
// const program = new Command();
|
|
166
|
-
|
|
167
|
-
// program
|
|
168
|
-
// .name('olang')
|
|
169
|
-
// .description('O-Lang CLI: run .olang workflows')
|
|
170
|
-
// .command('run <file>')
|
|
171
|
-
// .option('-r, --resolver <path>', 'Path to agent resolver (e.g., ./examples/groq-slack-resolver.js)')
|
|
172
|
-
// .option('-i, --input <k=v>', 'Input parameters', (val, acc = {}) => {
|
|
173
|
-
// const [k, v] = val.split('=');
|
|
174
|
-
// acc[k] = v;
|
|
175
|
-
// return acc;
|
|
176
|
-
// }, {})
|
|
177
|
-
// .action(async (file, options) => {
|
|
178
|
-
// try {
|
|
179
|
-
// const content = fs.readFileSync(file, 'utf8');
|
|
180
|
-
// const workflow = parse(content);
|
|
181
|
-
// const resolver = loadResolver(options.resolver);
|
|
182
|
-
// const result = await execute(workflow, options.input, resolver);
|
|
183
|
-
// console.log('\n=== Workflow Result ===');
|
|
184
|
-
// console.log(JSON.stringify(result, null, 2));
|
|
185
|
-
// } catch (err) {
|
|
186
|
-
// console.error('â Error:', err.message);
|
|
187
|
-
// process.exit(1);
|
|
188
|
-
// }
|
|
189
|
-
// });
|
|
190
|
-
|
|
191
|
-
// program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@o-lang/olang",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"author": "Olalekan Ogundipe <info@workfily.com>",
|
|
5
5
|
"description": "O-Lang: A governance language for user-directed, rule-enforced agent workflows",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -18,11 +18,22 @@
|
|
|
18
18
|
"commander": "^12.0.0",
|
|
19
19
|
"dotenv": "^17.2.3"
|
|
20
20
|
},
|
|
21
|
-
"keywords": [
|
|
21
|
+
"keywords": [
|
|
22
|
+
"agent",
|
|
23
|
+
"governance",
|
|
24
|
+
"workflow",
|
|
25
|
+
"llm",
|
|
26
|
+
"automation",
|
|
27
|
+
"olang",
|
|
28
|
+
"ai"
|
|
29
|
+
],
|
|
22
30
|
"license": "MIT",
|
|
23
31
|
"repository": {
|
|
24
32
|
"type": "git",
|
|
25
|
-
"url": "https://github.com/O-Lang-Central/olang-kernel.git"
|
|
33
|
+
"url": "git+https://github.com/O-Lang-Central/olang-kernel.git"
|
|
26
34
|
},
|
|
27
|
-
"homepage": "https://github.com/O-Lang-Central/olang-kernel"
|
|
28
|
-
|
|
35
|
+
"homepage": "https://github.com/O-Lang-Central/olang-kernel",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/parser.js
CHANGED
|
@@ -33,7 +33,7 @@ function parse(code) {
|
|
|
33
33
|
stepNumber: parseInt(stepMatch[1], 10),
|
|
34
34
|
actionRaw: stepMatch[2].trim(),
|
|
35
35
|
saveAs: null,
|
|
36
|
-
constraints: {}
|
|
36
|
+
constraints: {}
|
|
37
37
|
});
|
|
38
38
|
i++;
|
|
39
39
|
continue;
|
|
@@ -47,7 +47,7 @@ function parse(code) {
|
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
// Constraint
|
|
50
|
+
// Constraint
|
|
51
51
|
const constraintMatch = line.match(/^Constraint:\s*(.+)$/i);
|
|
52
52
|
if (constraintMatch && workflow.steps.length > 0) {
|
|
53
53
|
const lastStep = workflow.steps[workflow.steps.length - 1];
|
|
@@ -88,7 +88,7 @@ function parse(code) {
|
|
|
88
88
|
body.push(lines[i]);
|
|
89
89
|
i++;
|
|
90
90
|
}
|
|
91
|
-
if (i < lines.length) i++;
|
|
91
|
+
if (i < lines.length) i++;
|
|
92
92
|
workflow.steps.push({ type: 'if', condition, body: parseBlock(body) });
|
|
93
93
|
continue;
|
|
94
94
|
}
|
|
@@ -199,6 +199,32 @@ function parse(code) {
|
|
|
199
199
|
continue;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
// --- New: Use <Tool> ---
|
|
203
|
+
const useMatch = line.match(/^Use\s+(.+)$/i);
|
|
204
|
+
if (useMatch) {
|
|
205
|
+
workflow.steps.push({
|
|
206
|
+
type: 'use',
|
|
207
|
+
tool: useMatch[1].trim(),
|
|
208
|
+
saveAs: null,
|
|
209
|
+
constraints: {}
|
|
210
|
+
});
|
|
211
|
+
i++;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// --- New: Ask <Target> ---
|
|
216
|
+
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
217
|
+
if (askMatch) {
|
|
218
|
+
workflow.steps.push({
|
|
219
|
+
type: 'ask',
|
|
220
|
+
target: askMatch[1].trim(),
|
|
221
|
+
saveAs: null,
|
|
222
|
+
constraints: {}
|
|
223
|
+
});
|
|
224
|
+
i++;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
|
|
202
228
|
i++;
|
|
203
229
|
}
|
|
204
230
|
|
|
@@ -221,242 +247,40 @@ function parseBlock(lines) {
|
|
|
221
247
|
steps.push(current);
|
|
222
248
|
continue;
|
|
223
249
|
}
|
|
250
|
+
|
|
224
251
|
const saveMatch = line.match(/^Save as\s+(.+)$/i);
|
|
225
252
|
if (saveMatch && current) {
|
|
226
253
|
current.saveAs = saveMatch[1].trim();
|
|
227
254
|
}
|
|
255
|
+
|
|
228
256
|
const debriefMatch = line.match(/^Debrief\s+(\w+)\s+with\s+"(.+)"$/i);
|
|
229
257
|
if (debriefMatch) {
|
|
230
258
|
steps.push({ type: 'debrief', agent: debriefMatch[1], message: debriefMatch[2] });
|
|
231
259
|
}
|
|
260
|
+
|
|
232
261
|
const evolveMatch = line.match(/^Evolve\s+(\w+)\s+using\s+feedback:\s+"(.+)"$/i);
|
|
233
262
|
if (evolveMatch) {
|
|
234
263
|
steps.push({ type: 'evolve', agent: evolveMatch[1], feedback: evolveMatch[2] });
|
|
235
264
|
}
|
|
265
|
+
|
|
236
266
|
const promptMatch = line.match(/^Prompt user to\s+"(.+)"$/i);
|
|
237
267
|
if (promptMatch) {
|
|
238
268
|
steps.push({ type: 'prompt', question: promptMatch[1], saveAs: null });
|
|
239
269
|
}
|
|
270
|
+
|
|
271
|
+
// New: Use <Tool>
|
|
272
|
+
const useMatch = line.match(/^Use\s+(.+)$/i);
|
|
273
|
+
if (useMatch) {
|
|
274
|
+
steps.push({ type: 'use', tool: useMatch[1].trim(), saveAs: null, constraints: {} });
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// New: Ask <Target>
|
|
278
|
+
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
279
|
+
if (askMatch) {
|
|
280
|
+
steps.push({ type: 'ask', target: askMatch[1].trim(), saveAs: null, constraints: {} });
|
|
281
|
+
}
|
|
240
282
|
}
|
|
241
283
|
return steps;
|
|
242
284
|
}
|
|
243
285
|
|
|
244
286
|
module.exports = { parse };
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// // src/parser.js
|
|
253
|
-
// function parse(code) {
|
|
254
|
-
// const lines = code
|
|
255
|
-
// .split(/\r?\n/)
|
|
256
|
-
// .map(l => l.trim())
|
|
257
|
-
// .filter(l => l && !l.startsWith('#') && !l.startsWith('//'));
|
|
258
|
-
|
|
259
|
-
// const workflow = {
|
|
260
|
-
// name: 'Unnamed Workflow',
|
|
261
|
-
// parameters: [],
|
|
262
|
-
// steps: [],
|
|
263
|
-
// returnValues: []
|
|
264
|
-
// };
|
|
265
|
-
|
|
266
|
-
// let i = 0;
|
|
267
|
-
// while (i < lines.length) {
|
|
268
|
-
// let line = lines[i];
|
|
269
|
-
|
|
270
|
-
// // Workflow
|
|
271
|
-
// const wfMatch = line.match(/^Workflow\s+"([^"]+)"(?:\s+with\s+(.+))?/i);
|
|
272
|
-
// if (wfMatch) {
|
|
273
|
-
// workflow.name = wfMatch[1];
|
|
274
|
-
// workflow.parameters = wfMatch[2] ? wfMatch[2].split(',').map(p => p.trim()) : [];
|
|
275
|
-
// i++;
|
|
276
|
-
// continue;
|
|
277
|
-
// }
|
|
278
|
-
|
|
279
|
-
// // Step
|
|
280
|
-
// const stepMatch = line.match(/^Step\s+(\d+)\s*:\s*(.+)$/i);
|
|
281
|
-
// if (stepMatch) {
|
|
282
|
-
// workflow.steps.push({
|
|
283
|
-
// type: 'action',
|
|
284
|
-
// stepNumber: parseInt(stepMatch[1], 10),
|
|
285
|
-
// actionRaw: stepMatch[2].trim(),
|
|
286
|
-
// saveAs: null
|
|
287
|
-
// });
|
|
288
|
-
// i++;
|
|
289
|
-
// continue;
|
|
290
|
-
// }
|
|
291
|
-
|
|
292
|
-
// // Save as
|
|
293
|
-
// const saveMatch = line.match(/^Save as\s+(.+)$/i);
|
|
294
|
-
// if (saveMatch && workflow.steps.length > 0) {
|
|
295
|
-
// workflow.steps[workflow.steps.length - 1].saveAs = saveMatch[1].trim();
|
|
296
|
-
// i++;
|
|
297
|
-
// continue;
|
|
298
|
-
// }
|
|
299
|
-
|
|
300
|
-
// // If
|
|
301
|
-
// const ifMatch = line.match(/^If\s+(.+)\s+then$/i);
|
|
302
|
-
// if (ifMatch) {
|
|
303
|
-
// const condition = ifMatch[1].trim();
|
|
304
|
-
// const body = [];
|
|
305
|
-
// i++;
|
|
306
|
-
// while (i < lines.length && !/^\s*End If\s*$/i.test(lines[i])) {
|
|
307
|
-
// body.push(lines[i]);
|
|
308
|
-
// i++;
|
|
309
|
-
// }
|
|
310
|
-
// if (i < lines.length) i++; // skip 'End If'
|
|
311
|
-
// workflow.steps.push({ type: 'if', condition, body: parseBlock(body) });
|
|
312
|
-
// continue;
|
|
313
|
-
// }
|
|
314
|
-
|
|
315
|
-
// // Parallel
|
|
316
|
-
// const parMatch = line.match(/^Run in parallel$/i);
|
|
317
|
-
// if (parMatch) {
|
|
318
|
-
// const steps = [];
|
|
319
|
-
// i++;
|
|
320
|
-
// while (i < lines.length && !/^\s*End\s*$/i.test(lines[i])) {
|
|
321
|
-
// steps.push(lines[i]);
|
|
322
|
-
// i++;
|
|
323
|
-
// }
|
|
324
|
-
// if (i < lines.length) i++;
|
|
325
|
-
// workflow.steps.push({ type: 'parallel', steps: parseBlock(steps) });
|
|
326
|
-
// continue;
|
|
327
|
-
// }
|
|
328
|
-
|
|
329
|
-
// // Connect
|
|
330
|
-
// const connMatch = line.match(/^Connect\s+"([^"]+)"\s+using\s+"([^"]+)"$/i);
|
|
331
|
-
// if (connMatch) {
|
|
332
|
-
// workflow.steps.push({
|
|
333
|
-
// type: 'connect',
|
|
334
|
-
// resource: connMatch[1],
|
|
335
|
-
// endpoint: connMatch[2]
|
|
336
|
-
// });
|
|
337
|
-
// i++;
|
|
338
|
-
// continue;
|
|
339
|
-
// }
|
|
340
|
-
|
|
341
|
-
// // Agent ... uses ...
|
|
342
|
-
// const agentUseMatch = line.match(/^Agent\s+"([^"]+)"\s+uses\s+"([^"]+)"$/i);
|
|
343
|
-
// if (agentUseMatch) {
|
|
344
|
-
// workflow.steps.push({
|
|
345
|
-
// type: 'agent_use',
|
|
346
|
-
// logicalName: agentUseMatch[1],
|
|
347
|
-
// resource: agentUseMatch[2]
|
|
348
|
-
// });
|
|
349
|
-
// i++;
|
|
350
|
-
// continue;
|
|
351
|
-
// }
|
|
352
|
-
|
|
353
|
-
// // Debrief
|
|
354
|
-
// const debriefMatch = line.match(/^Debrief\s+(\w+)\s+with\s+"(.+)"$/i);
|
|
355
|
-
// if (debriefMatch) {
|
|
356
|
-
// workflow.steps.push({
|
|
357
|
-
// type: 'debrief',
|
|
358
|
-
// agent: debriefMatch[1],
|
|
359
|
-
// message: debriefMatch[2]
|
|
360
|
-
// });
|
|
361
|
-
// i++;
|
|
362
|
-
// continue;
|
|
363
|
-
// }
|
|
364
|
-
|
|
365
|
-
// // Evolve
|
|
366
|
-
// const evolveMatch = line.match(/^Evolve\s+(\w+)\s+using\s+feedback:\s+"(.+)"$/i);
|
|
367
|
-
// if (evolveMatch) {
|
|
368
|
-
// workflow.steps.push({
|
|
369
|
-
// type: 'evolve',
|
|
370
|
-
// agent: evolveMatch[1],
|
|
371
|
-
// feedback: evolveMatch[2]
|
|
372
|
-
// });
|
|
373
|
-
// i++;
|
|
374
|
-
// continue;
|
|
375
|
-
// }
|
|
376
|
-
|
|
377
|
-
// // Prompt
|
|
378
|
-
// const promptMatch = line.match(/^Prompt user to\s+"(.+)"$/i);
|
|
379
|
-
// if (promptMatch) {
|
|
380
|
-
// workflow.steps.push({
|
|
381
|
-
// type: 'prompt',
|
|
382
|
-
// question: promptMatch[1],
|
|
383
|
-
// saveAs: null
|
|
384
|
-
// });
|
|
385
|
-
// i++;
|
|
386
|
-
// continue;
|
|
387
|
-
// }
|
|
388
|
-
|
|
389
|
-
// // Persist
|
|
390
|
-
// const persistMatch = line.match(/^Persist\s+(.+)\s+to\s+"(.+)"$/i);
|
|
391
|
-
// if (persistMatch) {
|
|
392
|
-
// workflow.steps.push({
|
|
393
|
-
// type: 'persist',
|
|
394
|
-
// variable: persistMatch[1].trim(),
|
|
395
|
-
// target: persistMatch[2]
|
|
396
|
-
// });
|
|
397
|
-
// i++;
|
|
398
|
-
// continue;
|
|
399
|
-
// }
|
|
400
|
-
|
|
401
|
-
// // Emit
|
|
402
|
-
// const emitMatch = line.match(/^Emit\s+"(.+)"\s+with\s+(.+)$/i);
|
|
403
|
-
// if (emitMatch) {
|
|
404
|
-
// workflow.steps.push({
|
|
405
|
-
// type: 'emit',
|
|
406
|
-
// event: emitMatch[1],
|
|
407
|
-
// payload: emitMatch[2].trim()
|
|
408
|
-
// });
|
|
409
|
-
// i++;
|
|
410
|
-
// continue;
|
|
411
|
-
// }
|
|
412
|
-
|
|
413
|
-
// // Return
|
|
414
|
-
// const returnMatch = line.match(/^Return\s+(.+)$/i);
|
|
415
|
-
// if (returnMatch) {
|
|
416
|
-
// workflow.returnValues = returnMatch[1].split(',').map(v => v.trim());
|
|
417
|
-
// i++;
|
|
418
|
-
// continue;
|
|
419
|
-
// }
|
|
420
|
-
|
|
421
|
-
// i++;
|
|
422
|
-
// }
|
|
423
|
-
|
|
424
|
-
// return workflow;
|
|
425
|
-
// }
|
|
426
|
-
|
|
427
|
-
// function parseBlock(lines) {
|
|
428
|
-
// const steps = [];
|
|
429
|
-
// let current = null;
|
|
430
|
-
// for (const line of lines) {
|
|
431
|
-
// const stepMatch = line.match(/^Step\s+(\d+)\s*:\s*(.+)$/i);
|
|
432
|
-
// if (stepMatch) {
|
|
433
|
-
// current = {
|
|
434
|
-
// type: 'action',
|
|
435
|
-
// stepNumber: parseInt(stepMatch[1], 10),
|
|
436
|
-
// actionRaw: stepMatch[2].trim(),
|
|
437
|
-
// saveAs: null
|
|
438
|
-
// };
|
|
439
|
-
// steps.push(current);
|
|
440
|
-
// continue;
|
|
441
|
-
// }
|
|
442
|
-
// const saveMatch = line.match(/^Save as\s+(.+)$/i);
|
|
443
|
-
// if (saveMatch && current) {
|
|
444
|
-
// current.saveAs = saveMatch[1].trim();
|
|
445
|
-
// }
|
|
446
|
-
// const debriefMatch = line.match(/^Debrief\s+(\w+)\s+with\s+"(.+)"$/i);
|
|
447
|
-
// if (debriefMatch) {
|
|
448
|
-
// steps.push({ type: 'debrief', agent: debriefMatch[1], message: debriefMatch[2] });
|
|
449
|
-
// }
|
|
450
|
-
// const evolveMatch = line.match(/^Evolve\s+(\w+)\s+using\s+feedback:\s+"(.+)"$/i);
|
|
451
|
-
// if (evolveMatch) {
|
|
452
|
-
// steps.push({ type: 'evolve', agent: evolveMatch[1], feedback: evolveMatch[2] });
|
|
453
|
-
// }
|
|
454
|
-
// const promptMatch = line.match(/^Prompt user to\s+"(.+)"$/i);
|
|
455
|
-
// if (promptMatch) {
|
|
456
|
-
// steps.push({ type: 'prompt', question: promptMatch[1], saveAs: null });
|
|
457
|
-
// }
|
|
458
|
-
// }
|
|
459
|
-
// return steps;
|
|
460
|
-
// }
|
|
461
|
-
|
|
462
|
-
// module.exports = { parse };
|
package/src/runtime.js
CHANGED
|
@@ -35,7 +35,6 @@ class RuntimeAPI {
|
|
|
35
35
|
return path.split('.').reduce((o, k) => (o && o[k] !== undefined) ? o[k] : undefined, obj);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// đ Find the last "Ask ... Save as ..." step that can be evolved
|
|
39
38
|
findLastSummaryStep() {
|
|
40
39
|
for (let i = this.workflowSteps.length - 1; i >= 0; i--) {
|
|
41
40
|
const step = this.workflowSteps[i];
|
|
@@ -58,6 +57,20 @@ class RuntimeAPI {
|
|
|
58
57
|
break;
|
|
59
58
|
}
|
|
60
59
|
|
|
60
|
+
case 'use': {
|
|
61
|
+
// "Use <Tool>" step
|
|
62
|
+
const res = await agentResolver(`Use ${step.tool}`, this.context);
|
|
63
|
+
if (step.saveAs) this.context[step.saveAs] = res;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case 'ask': {
|
|
68
|
+
// "Ask <Target>" step
|
|
69
|
+
const res = await agentResolver(`Ask ${step.target}`, this.context);
|
|
70
|
+
if (step.saveAs) this.context[step.saveAs] = res;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
61
74
|
case 'if': {
|
|
62
75
|
if (this.evaluateCondition(step.condition, this.context)) {
|
|
63
76
|
for (const s of step.body) await this.executeStep(s, agentResolver);
|
|
@@ -86,7 +99,6 @@ class RuntimeAPI {
|
|
|
86
99
|
}
|
|
87
100
|
|
|
88
101
|
case 'evolve': {
|
|
89
|
-
// â
Runtime-enforced bounded evolution
|
|
90
102
|
const maxGen = step.constraints?.max_generations || 1;
|
|
91
103
|
if (maxGen < 1) {
|
|
92
104
|
this.context['improved_summary'] = this.context['summary'] || '';
|
|
@@ -100,34 +112,28 @@ class RuntimeAPI {
|
|
|
100
112
|
return;
|
|
101
113
|
}
|
|
102
114
|
|
|
103
|
-
const varName = summaryStep.saveAs;
|
|
115
|
+
const varName = summaryStep.saveAs;
|
|
104
116
|
let currentOutput = this.context[varName] || '';
|
|
105
117
|
|
|
106
|
-
// Run up to max_generations attempts
|
|
107
118
|
for (let attempt = 0; attempt < maxGen; attempt++) {
|
|
108
|
-
// Rebuild the original action with current context (re-interpolates {doc.text}, etc.)
|
|
109
119
|
let revisedAction = summaryStep.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
110
120
|
const val = this.getNested(this.context, path.trim());
|
|
111
121
|
return val !== undefined ? String(val) : `{${path}}`;
|
|
112
122
|
});
|
|
113
123
|
|
|
114
|
-
// Append improvement feedback on every attempt (including first)
|
|
115
124
|
if (step.feedback) {
|
|
116
|
-
revisedAction = revisedAction.replace(/(")
|
|
125
|
+
revisedAction = revisedAction.replace(/(")$/, `\n\n[IMPROVEMENT FEEDBACK: ${step.feedback}]$1`);
|
|
117
126
|
}
|
|
118
127
|
|
|
119
|
-
// Delegate ONLY the "Ask ..." action to the resolver
|
|
120
128
|
currentOutput = await agentResolver(revisedAction, this.context);
|
|
121
|
-
this.context[varName] = currentOutput;
|
|
129
|
+
this.context[varName] = currentOutput;
|
|
122
130
|
|
|
123
|
-
// Optional: emit debrief for observability
|
|
124
131
|
this.emit('debrief', {
|
|
125
132
|
agent: step.agent || 'Evolver',
|
|
126
133
|
message: `Evolve attempt ${attempt + 1}/${maxGen}: ${currentOutput.substring(0, 80)}...`
|
|
127
134
|
});
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
// â
Always expose final result as 'improved_summary' for downstream use
|
|
131
137
|
this.context['improved_summary'] = currentOutput;
|
|
132
138
|
break;
|
|
133
139
|
}
|
|
@@ -167,7 +173,7 @@ class RuntimeAPI {
|
|
|
167
173
|
|
|
168
174
|
async executeWorkflow(workflow, inputs, agentResolver) {
|
|
169
175
|
this.context = { ...inputs };
|
|
170
|
-
this.workflowSteps = workflow.steps;
|
|
176
|
+
this.workflowSteps = workflow.steps;
|
|
171
177
|
|
|
172
178
|
for (const step of workflow.steps) {
|
|
173
179
|
await this.executeStep(step, agentResolver);
|
|
@@ -187,127 +193,3 @@ async function execute(workflow, inputs, agentResolver) {
|
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
module.exports = { execute, RuntimeAPI };
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
// // src/runtime.js
|
|
193
|
-
// const fs = require('fs');
|
|
194
|
-
|
|
195
|
-
// class RuntimeAPI {
|
|
196
|
-
// constructor() {
|
|
197
|
-
// this.context = {};
|
|
198
|
-
// this.resources = {};
|
|
199
|
-
// this.agentMap = {};
|
|
200
|
-
// this.events = {};
|
|
201
|
-
// }
|
|
202
|
-
|
|
203
|
-
// on(eventName, cb) {
|
|
204
|
-
// if (!this.events[eventName]) this.events[eventName] = [];
|
|
205
|
-
// this.events[eventName].push(cb);
|
|
206
|
-
// }
|
|
207
|
-
|
|
208
|
-
// emit(eventName, payload) {
|
|
209
|
-
// if (this.events[eventName]) {
|
|
210
|
-
// this.events[eventName].forEach(cb => cb(payload));
|
|
211
|
-
// }
|
|
212
|
-
// }
|
|
213
|
-
|
|
214
|
-
// evaluateCondition(cond, ctx) {
|
|
215
|
-
// cond = cond.trim();
|
|
216
|
-
// const eq = cond.match(/^\{(.+)\}\s+equals\s+"(.*)"$/);
|
|
217
|
-
// if (eq) return this.getNested(ctx, eq[1]) === eq[2];
|
|
218
|
-
// const gt = cond.match(/^\{(.+)\}\s+greater than\s+(\d+\.?\d*)$/);
|
|
219
|
-
// if (gt) return parseFloat(this.getNested(ctx, gt[1])) > parseFloat(gt[2]);
|
|
220
|
-
// return Boolean(this.getNested(ctx, cond.replace(/\{|\}/g, '')));
|
|
221
|
-
// }
|
|
222
|
-
|
|
223
|
-
// getNested(obj, path) {
|
|
224
|
-
// if (!path) return undefined;
|
|
225
|
-
// return path.split('.').reduce((o, k) => (o && o[k] !== undefined) ? o[k] : undefined, obj);
|
|
226
|
-
// }
|
|
227
|
-
|
|
228
|
-
// async executeStep(step, agentResolver) {
|
|
229
|
-
// switch (step.type) {
|
|
230
|
-
// case 'action':
|
|
231
|
-
// // â
Support nested interpolation: {doc.text}, {user.name}, etc.
|
|
232
|
-
// const action = step.actionRaw.replace(/\{([^\}]+)\}/g, (_, path) => {
|
|
233
|
-
// const value = this.getNested(this.context, path.trim());
|
|
234
|
-
// return value !== undefined ? String(value) : `{${path}}`;
|
|
235
|
-
// });
|
|
236
|
-
// const res = await agentResolver(action, this.context);
|
|
237
|
-
// if (step.saveAs) this.context[step.saveAs] = res;
|
|
238
|
-
// break;
|
|
239
|
-
|
|
240
|
-
// case 'if':
|
|
241
|
-
// if (this.evaluateCondition(step.condition, this.context)) {
|
|
242
|
-
// for (const s of step.body) await this.executeStep(s, agentResolver);
|
|
243
|
-
// }
|
|
244
|
-
// break;
|
|
245
|
-
|
|
246
|
-
// case 'parallel':
|
|
247
|
-
// await Promise.all(step.steps.map(s => this.executeStep(s, agentResolver)));
|
|
248
|
-
// break;
|
|
249
|
-
|
|
250
|
-
// case 'connect':
|
|
251
|
-
// this.resources[step.resource] = step.endpoint;
|
|
252
|
-
// break;
|
|
253
|
-
|
|
254
|
-
// case 'agent_use':
|
|
255
|
-
// this.agentMap[step.logicalName] = step.resource;
|
|
256
|
-
// break;
|
|
257
|
-
|
|
258
|
-
// case 'debrief':
|
|
259
|
-
// this.emit('debrief', { agent: step.agent, message: step.message });
|
|
260
|
-
// break;
|
|
261
|
-
|
|
262
|
-
// case 'evolve':
|
|
263
|
-
// // Pass evolve as a structured action (optional: could use dedicated handler)
|
|
264
|
-
// await agentResolver(`Evolve ${step.agent} using feedback: "${step.feedback}"`, this.context);
|
|
265
|
-
// break;
|
|
266
|
-
|
|
267
|
-
// case 'prompt':
|
|
268
|
-
// const input = await this.getUserInput(step.question);
|
|
269
|
-
// if (step.saveAs) this.context[step.saveAs] = input;
|
|
270
|
-
// break;
|
|
271
|
-
|
|
272
|
-
// case 'persist':
|
|
273
|
-
// const val = this.context[step.variable];
|
|
274
|
-
// fs.appendFileSync(step.target, JSON.stringify(val) + '\n', 'utf8');
|
|
275
|
-
// break;
|
|
276
|
-
|
|
277
|
-
// case 'emit':
|
|
278
|
-
// const payload = step.payload ? this.getNested(this.context, step.payload) : undefined;
|
|
279
|
-
// this.emit(step.event, payload || step.payload);
|
|
280
|
-
// break;
|
|
281
|
-
// }
|
|
282
|
-
// }
|
|
283
|
-
|
|
284
|
-
// async getUserInput(question) {
|
|
285
|
-
// return new Promise(resolve => {
|
|
286
|
-
// process.stdout.write(`${question}: `);
|
|
287
|
-
// process.stdin.resume();
|
|
288
|
-
// process.stdin.once('data', data => {
|
|
289
|
-
// process.stdin.pause();
|
|
290
|
-
// resolve(data.toString().trim());
|
|
291
|
-
// });
|
|
292
|
-
// });
|
|
293
|
-
// }
|
|
294
|
-
|
|
295
|
-
// async executeWorkflow(workflow, inputs, agentResolver) {
|
|
296
|
-
// this.context = { ...inputs };
|
|
297
|
-
// for (const step of workflow.steps) {
|
|
298
|
-
// await this.executeStep(step, agentResolver);
|
|
299
|
-
// }
|
|
300
|
-
// const result = {};
|
|
301
|
-
// for (const key of workflow.returnValues) {
|
|
302
|
-
// result[key] = this.getNested(this.context, key);
|
|
303
|
-
// }
|
|
304
|
-
// return result;
|
|
305
|
-
// }
|
|
306
|
-
// }
|
|
307
|
-
|
|
308
|
-
// async function execute(workflow, inputs, agentResolver) {
|
|
309
|
-
// const rt = new RuntimeAPI();
|
|
310
|
-
// return rt.executeWorkflow(workflow, inputs, agentResolver);
|
|
311
|
-
// }
|
|
312
|
-
|
|
313
|
-
// module.exports = { execute, RuntimeAPI };
|