@o-lang/olang 1.2.1 → 1.2.3
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 +13 -9
- package/src/parser/index.js +38 -35
- package/src/runtime/RuntimeAPI.js +52 -27
package/package.json
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@o-lang/olang",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
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",
|
|
7
|
-
"bin": {
|
|
8
|
-
|
|
9
|
-
},
|
|
7
|
+
"bin": {
|
|
8
|
+
"olang": "./cli/olang.js"
|
|
9
|
+
},
|
|
10
10
|
"files": [
|
|
11
11
|
"cli.js",
|
|
12
12
|
"src/"
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
|
-
"start": "node cli.js"
|
|
15
|
+
"start": "node cli.js",
|
|
16
|
+
"test": "jest"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
"commander": "^12.0.0",
|
|
20
|
+
"dotenv": "^17.2.3",
|
|
21
|
+
"fastify": "^4.26.0",
|
|
22
|
+
"lodash": "^4.17.21"
|
|
22
23
|
},
|
|
23
24
|
"keywords": [
|
|
24
25
|
"agent",
|
|
@@ -37,5 +38,8 @@
|
|
|
37
38
|
"homepage": "https://github.com/O-Lang-Central/olang-kernel",
|
|
38
39
|
"publishConfig": {
|
|
39
40
|
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"jest": "^30.2.0"
|
|
40
44
|
}
|
|
41
45
|
}
|
package/src/parser/index.js
CHANGED
|
@@ -385,18 +385,18 @@ function parseWorkflowLines(lines, filename) {
|
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
// Ask (for Notify/resolver calls) - ✅ PRESERVE TARGET EXACTLY (NO NORMALIZATION)
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
388
|
+
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
389
|
+
if (askMatch) {
|
|
390
|
+
flushCurrentStep();
|
|
391
|
+
workflow.steps.push({
|
|
392
|
+
type: 'action',
|
|
393
|
+
actionRaw: `Action ${askMatch[1].trim()}`,
|
|
394
|
+
stepNumber: workflow.steps.length + 1,
|
|
395
|
+
saveAs: null,
|
|
396
|
+
constraints: {}
|
|
397
|
+
});
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
400
|
|
|
401
401
|
// Return
|
|
402
402
|
const returnMatch = line.match(/^Return\s+(.+)$/i);
|
|
@@ -530,30 +530,33 @@ function parseBlock(lines) {
|
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
// Use in block - ✅ PRESERVE TOOL EXACTLY (NO NORMALIZATION)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
533
|
+
const useMatch = line.match(/^Use\s+(.+)$/i);
|
|
534
|
+
if (useMatch) {
|
|
535
|
+
flushCurrentStep();
|
|
536
|
+
workflow.steps.push({
|
|
537
|
+
type: 'action',
|
|
538
|
+
actionRaw: `Action ${useMatch[1].trim()}`,
|
|
539
|
+
stepNumber: workflow.steps.length + 1,
|
|
540
|
+
saveAs: null,
|
|
541
|
+
constraints: {}
|
|
542
|
+
});
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
// Ask in block — CANONICALIZE AT PARSE TIME
|
|
548
|
+
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
549
|
+
if (askMatch) {
|
|
550
|
+
flush();
|
|
551
|
+
steps.push({
|
|
552
|
+
type: 'action',
|
|
553
|
+
actionRaw: `Action ${askMatch[1].trim()}`,
|
|
554
|
+
saveAs: null,
|
|
555
|
+
constraints: {}
|
|
556
|
+
});
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
544
559
|
|
|
545
|
-
// Ask in block - ✅ PRESERVE TARGET EXACTLY (NO NORMALIZATION)
|
|
546
|
-
const askMatch = line.match(/^Ask\s+(.+)$/i);
|
|
547
|
-
if (askMatch) {
|
|
548
|
-
flush();
|
|
549
|
-
steps.push({
|
|
550
|
-
type: 'ask',
|
|
551
|
-
target: askMatch[1].trim(), // ← PRESERVED EXACTLY
|
|
552
|
-
saveAs: null,
|
|
553
|
-
constraints: {}
|
|
554
|
-
});
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
560
|
|
|
558
561
|
// Constraint inside block
|
|
559
562
|
const constraintMatch = line.match(/^Constraint:\s*(.+)$/i);
|
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
|
|
5
5
|
class RuntimeAPI {
|
|
6
6
|
constructor({ verbose = false } = {}) {
|
|
7
|
-
|
|
7
|
+
// console.log('✅ KERNEL FIX VERIFIED - Unwrapping active');
|
|
8
8
|
this.context = {};
|
|
9
9
|
this.resources = {};
|
|
10
10
|
this.agentMap = {};
|
|
@@ -552,34 +552,59 @@ class RuntimeAPI {
|
|
|
552
552
|
break;
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
555
|
+
case 'action': {
|
|
556
|
+
// 🔒 Interpolate workflow variables first
|
|
557
|
+
let action = this._safeInterpolate(
|
|
558
|
+
step.actionRaw,
|
|
559
|
+
this.context,
|
|
560
|
+
'action step'
|
|
561
|
+
);
|
|
558
562
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
return this.getNested(this.context, s.replace(/^\{|\}$/g, ''));
|
|
566
|
-
});
|
|
567
|
-
if (this.mathFunctions[fn]) {
|
|
568
|
-
const value = this.mathFunctions[fn](...args);
|
|
569
|
-
if (step.saveAs) this.context[step.saveAs] = value;
|
|
570
|
-
break;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
563
|
+
// ✅ CANONICALIZATION: Normalize DSL verbs → runtime Action
|
|
564
|
+
if (action.startsWith('Ask ')) {
|
|
565
|
+
action = 'Action ' + action.slice(4);
|
|
566
|
+
} else if (action.startsWith('Use ')) {
|
|
567
|
+
action = 'Action ' + action.slice(4);
|
|
568
|
+
}
|
|
573
569
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
570
|
+
// ❌ Reject non-canonical runtime actions early
|
|
571
|
+
if (!action.startsWith('Action ')) {
|
|
572
|
+
throw new Error(
|
|
573
|
+
`[O-Lang SAFETY] Non-canonical action received: "${action}"\n` +
|
|
574
|
+
` → Expected format: Action <resolver> <args>\n` +
|
|
575
|
+
` → This indicates a kernel or workflow authoring error.`
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ✅ Inline math support (language feature)
|
|
580
|
+
const mathCall = action.match(
|
|
581
|
+
/^(add|subtract|multiply|divide|sum|avg|min|max|round|floor|ceil|abs)\((.*)\)$/i
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
if (mathCall) {
|
|
585
|
+
const fn = mathCall[1].toLowerCase();
|
|
586
|
+
const args = mathCall[2].split(',').map(s => {
|
|
587
|
+
s = s.trim();
|
|
588
|
+
if (!isNaN(s)) return parseFloat(s);
|
|
589
|
+
return this.getNested(this.context, s.replace(/^\{|\}$/g, ''));
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
if (this.mathFunctions[fn]) {
|
|
593
|
+
const value = this.mathFunctions[fn](...args);
|
|
594
|
+
if (step.saveAs) this.context[step.saveAs] = value;
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ✅ Resolver dispatch receives ONLY canonical actions
|
|
600
|
+
const rawResult = await runResolvers(action);
|
|
601
|
+
const unwrapped = this._unwrapResolverResult(rawResult);
|
|
602
|
+
|
|
603
|
+
if (step.saveAs) {
|
|
604
|
+
this.context[step.saveAs] = unwrapped;
|
|
605
|
+
}
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
583
608
|
|
|
584
609
|
case 'use': {
|
|
585
610
|
// ✅ SAFE INTERPOLATION for tool name
|