@o-lang/olang 1.2.30 → 1.2.32

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@o-lang/olang",
3
- "version": "1.2.30",
3
+ "version": "1.2.32",
4
4
  "author": "Olalekan Ogundipe <info@olang.cloud>",
5
5
  "description": "O-Lang: A governance language for user-directed, rule-enforced agent workflows",
6
6
  "main": "./src/runtime/index.js",
@@ -305,7 +305,7 @@ function parseWorkflowLines(lines, filename) {
305
305
  continue;
306
306
  }
307
307
 
308
- // ✅ ADD: Set keyword (e.g., Set analysis_result = "")
308
+ // ✅ ADD: Set keyword (e.g., Set analysis_result = "")
309
309
  const setMatch = line.match(/^Set\s+(\w+)\s*=\s*(.+)$/i);
310
310
  if (setMatch) {
311
311
  flushCurrentStep();
@@ -399,38 +399,41 @@ function parseWorkflowLines(lines, filename) {
399
399
  }
400
400
 
401
401
  // Ask (for Notify/resolver calls) - ✅ PRESERVE TARGET EXACTLY (NO NORMALIZATION)
402
- const askMatch = line.match(/^Ask\s+(.+)$/i);
403
- if (askMatch) {
404
- flushCurrentStep();
405
- let actionContent = askMatch[1].trim();
406
-
407
- // ✅ Multiline heredoc support: Ask llm-groq """
408
- if (actionContent.endsWith('"""')) {
409
- // Consume lines until closing """
410
- let multiline = actionContent.slice(0, -3).trim() + ' ';
411
- while (i < lines.length) {
412
- const nextLine = lines[i++].trim();
413
- if (nextLine === '"""') break;
414
- multiline += nextLine + ' ';
415
- }
416
- actionContent = multiline.trim();
417
- }
402
+ const askMatch = line.match(/^Ask\s+(.+)$/i);
403
+ if (askMatch) {
404
+ flushCurrentStep();
405
+ let actionContent = askMatch[1].trim();
406
+
407
+ // ✅ Multiline heredoc support: Ask llm-groq """
408
+ if (actionContent.endsWith('"""')) {
409
+ // Consume lines until closing """
410
+ let multiline = actionContent.slice(0, -3).trim() + ' ';
411
+ while (i < lines.length) {
412
+ const nextLine = lines[i++].trim();
413
+ if (nextLine === '"""') break;
414
+ multiline += nextLine + ' ';
415
+ }
416
+ actionContent = multiline.trim();
417
+ }
418
418
 
419
- workflow.steps.push({
420
- type: 'action',
421
- actionRaw: `Action ${actionContent}`,
422
- stepNumber: workflow.steps.length + 1,
423
- saveAs: null,
424
- constraints: {}
425
- });
426
- continue;
427
- }
419
+ workflow.steps.push({
420
+ type: 'action',
421
+ actionRaw: `Action ${actionContent}`,
422
+ stepNumber: workflow.steps.length + 1,
423
+ saveAs: null,
424
+ constraints: {}
425
+ });
426
+ continue;
427
+ }
428
428
 
429
- // Return
429
+ // ✅ ADD: Return keyword support (ensures wf.returnValues is populated)
430
430
  const returnMatch = line.match(/^Return\s+(.+)$/i);
431
431
  if (returnMatch) {
432
432
  flushCurrentStep();
433
- workflow.returnValues = returnMatch[1].split(',').map(r => r.trim()).filter(r => r !== '');
433
+ workflow.returnValues = returnMatch[1]
434
+ .split(',')
435
+ .map(r => r.trim())
436
+ .filter(r => r !== '');
434
437
  continue;
435
438
  }
436
439
 
@@ -603,7 +606,7 @@ function parseBlock(lines) {
603
606
  continue;
604
607
  }
605
608
 
606
- // ✅ ADD: Set keyword inside blocks (e.g., Set analysis_result = "")
609
+ // ✅ ADD: Set keyword inside blocks (e.g., Set analysis_result = "")
607
610
  const setMatch = line.match(/^Set\s+(\w+)\s*=\s*(.+)$/i);
608
611
  if (setMatch) {
609
612
  flush(); // Flush any pending step
@@ -615,6 +618,15 @@ function parseBlock(lines) {
615
618
  });
616
619
  continue;
617
620
  }
621
+
622
+ // ✅ ADD: Return keyword inside blocks (rare but supported)
623
+ const returnMatch = line.match(/^Return\s+(.+)$/i);
624
+ if (returnMatch) {
625
+ flush();
626
+ // Note: Return inside blocks is unusual; this just parses it
627
+ continue;
628
+ }
629
+
618
630
  // Fallback
619
631
  if (current) {
620
632
  current.actionRaw += ' ' + line; // ← PRESERVED EXACTLY (no normalizeAction)
@@ -690,15 +690,38 @@ class RuntimeAPI {
690
690
  abs: a => Math.abs(a)
691
691
  };
692
692
 
693
- evaluateMath(expr) {
693
+ evaluateMath(expr) {
694
+ // ✅ Handle quoted string literals with interpolation: "{var}" → interpolated string
695
+ if (typeof expr === 'string') {
696
+ const trimmed = expr.trim();
697
+
698
+ // Check if it's a quoted string (single or double quotes)
699
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
700
+ (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
701
+ // Extract the inner content
702
+ let inner = trimmed.slice(1, -1);
703
+
704
+ // Perform interpolation: replace {var} with context values
705
+ inner = inner.replace(/\{([^\}]+)\}/g, (_, path) => {
706
+ const value = this.getNested(this.context, path.trim());
707
+ return value !== undefined ? String(value) : `{${path}}`;
708
+ });
709
+
710
+ return inner;
711
+ }
712
+ }
713
+
714
+ // ── Original math evaluation logic (unchanged) ──────────────────────────
694
715
  expr = expr.replace(/\{([^\}]+)\}/g, (_, path) => {
695
716
  const value = this.getNested(this.context, path.trim());
696
717
  if (typeof value === 'string') return `"${value.replace(/"/g, '\\"')}"`;
697
718
  return value !== undefined ? value : 0;
698
719
  });
720
+
699
721
  const funcNames = Object.keys(this.mathFunctions);
700
722
  const safeFunc = {};
701
723
  funcNames.forEach(fn => safeFunc[fn] = this.mathFunctions[fn]);
724
+
702
725
  try {
703
726
  const f = new Function(...funcNames, `return ${expr};`);
704
727
  return f(...funcNames.map(fn => safeFunc[fn]));