@o-lang/olang 1.2.5 โ†’ 1.2.7

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.5",
3
+ "version": "1.2.7",
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",
@@ -331,40 +331,101 @@ class RuntimeAPI {
331
331
  });
332
332
  }
333
333
 
334
- // -----------------------------
335
- // โœ… KERNEL-LEVEL LLM HALLUCINATION PREVENTION (ZERO WORKFLOW CHANGES)
336
- // -----------------------------
337
- _validateLLMOutput(output, actionContext) {
338
- if (!output || typeof output !== 'string') return { passed: true };
339
-
340
- // ๐Ÿ”‘ CRITICAL: Extract ONLY allowed capabilities from workflow allowlist
341
- const allowedCapabilities = Array.from(this.allowedResolvers)
342
- .filter(name => !name.startsWith('llm-') && name !== 'builtInMathResolver')
343
- .map(name => name.replace('@o-lang/', '').replace(/-resolver$/, ''));
344
-
345
- // ๐Ÿ”’ Block capability hallucinations (claims to do things outside allowlist)
346
- const forbiddenPatterns = [
347
- { pattern: /\b(transfer|send|wire|pay|withdraw|deposit)\b/i, capability: 'transfer' },
348
- { pattern: /\b(create|open|close|delete)\s+(account|profile)\b/i, capability: 'account_management' },
349
- { pattern: /\bI (can|will|am able to)\s+(transfer|pay|send)/i, capability: 'unauthorized_action' }
350
- ];
351
-
352
- for (const { pattern, capability } of forbiddenPatterns) {
353
- if (pattern.test(output)) {
354
- // โœ… Only block if capability NOT in allowlist
355
- if (!allowedCapabilities.some(c => c.includes(capability) || c.includes('transfer'))) {
356
- return {
357
- passed: false,
358
- reason: `Hallucinated "${capability}" capability (not in workflow allowlist: ${allowedCapabilities.join(', ') || 'none'})`,
359
- detected: output.match(pattern)?.[0] || 'unknown'
360
- };
361
- }
334
+ // -----------------------------
335
+ // โœ… KERNEL-LEVEL LLM HALLUCINATION PREVENTION (MULTILINGUAL SEMANTIC SAFETY)
336
+ // -----------------------------
337
+ _validateLLMOutput(output, actionContext) {
338
+ if (!output || typeof output !== 'string') return { passed: true };
339
+
340
+ // ๐Ÿ”‘ Extract allowed capabilities from workflow allowlist
341
+ const allowedCapabilities = Array.from(this.allowedResolvers)
342
+ .filter(name => !name.startsWith('llm-') && name !== 'builtInMathResolver')
343
+ .map(name => name.replace('@o-lang/', '').replace(/-resolver$/, ''));
344
+
345
+ // ๐Ÿ”’ MULTILINGUAL INTENT DETECTION (Deterministic, No LLM Required)
346
+ // Patterns ordered by language family โ†’ script โ†’ frequency
347
+ const forbiddenPatterns = [
348
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
349
+ // ๐Ÿ‡ณ๐Ÿ‡ฌ NIGERIAN LANGUAGES (Priority for your mission)
350
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
351
+
352
+ // Yoruba (yo) - Latin script
353
+ { pattern: /\b(fi\s+(?:owo|แบนฬ€wแปฬ€|ewo|ku|fun|s'แปkแปแป))\b/i, capability: 'transfer', lang: 'yo' },
354
+ { pattern: /\b(san\s+(?:owo|แบนฬ€wแปฬ€|ewo|fun|wo|lแบนsแบนkแบนsแบน))\b/i, capability: 'payment', lang: 'yo' },
355
+ { pattern: /\b(gba\s+owo)\b/i, capability: 'withdrawal', lang: 'yo' },
356
+ { pattern: /\b(mo\s+ti\s+(?:fi|san))\b/i, capability: 'unauthorized_action', lang: 'yo' }, // "I have transferred/paid"
357
+
358
+ // Hausa (ha) - Latin script
359
+ { pattern: /\b(ciyar\s*(?:da)?|ciya\s*(?:da)?)\b/i, capability: 'transfer', lang: 'ha' },
360
+ { pattern: /\b(biya\s*(?:da)?|sauce\s+kuษ—i)\b/i, capability: 'payment', lang: 'ha' },
361
+ { pattern: /\b(sahawa\s+kuษ—i|sahawar)\b/i, capability: 'withdrawal', lang: 'ha' },
362
+ { pattern: /\b(ina\s+(?:ciyar|biya))\b/i, capability: 'unauthorized_action', lang: 'ha' }, // "I am transferring/paying"
363
+
364
+ // Igbo (ig) - Latin script
365
+ { pattern: /\b(zipu\s+(?:ego|moni|isi|na))\b/i, capability: 'transfer', lang: 'ig' },
366
+ { pattern: /\b(buru\s+(?:ego|moni|isi))\b/i, capability: 'transfer', lang: 'ig' }, // "carry/send money"
367
+ { pattern: /\b(tinye\s+(?:ego|moni|isi))\b/i, capability: 'deposit', lang: 'ig' },
368
+ { pattern: /\b(m\s+(?:ziri|buru|zipuru))\b/i, capability: 'unauthorized_action', lang: 'ig' }, // "I sent/carried"
369
+
370
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
371
+ // ๐ŸŒ GLOBAL LANGUAGES (Critical mass coverage)
372
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
373
+
374
+ // English (en) - Baseline
375
+ { pattern: /\b(transfer|transferred|transferring|send|sent|sending|wire|wired|pay|paid|paying|withdraw|withdrew|withdrawal|deposit|deposited)\b/i, capability: 'financial_action', lang: 'en' },
376
+ { pattern: /\bI\s+(?:can|will|am able to|have|'ve|did)\s+(?:transfer|send|pay|withdraw|deposit)\b/i, capability: 'unauthorized_action', lang: 'en' },
377
+
378
+ // French (fr) - Latin script
379
+ { pattern: /\b(transfรฉrer|transfรฉrรฉ|transfรฉrant|envoyer|envoyรฉ|payer|payรฉ|retirer|retirรฉ|dรฉposer|dรฉposรฉ)\b/i, capability: 'financial_action', lang: 'fr' },
380
+ { pattern: /\b(je\s+(?:peux|vais|ai)\s+(?:transfรฉrer|envoyer|payer))\b/i, capability: 'unauthorized_action', lang: 'fr' }, // "I can transfer/send/pay"
381
+
382
+ // Arabic (ar) - Right-to-left script (Unicode ranges)
383
+ { pattern: /[\u0621-\u064A]{0,3}(?:ุญูˆู‘ู„|ุญูˆู„|ุฃุฑุณู„|ุงุฑุณู„|ุงุฏูุน|ุงุฏูุน|ุงูˆุฏุน|ุงูˆุฏุน|ุณุญุจ|ุงุณุชุฎุฑุฌ)[\u0621-\u064A]{0,3}/u, capability: 'financial_action', lang: 'ar' },
384
+ { pattern: /[\u0621-\u064A]{0,3}(?:ุฃู†ุง)\s*(?:ุญูˆู‘ู„ุช|ุฃุฑุณู„ุช|ุฏูุนุช)[\u0621-\u064A]{0,3}/u, capability: 'unauthorized_action', lang: 'ar' }, // "I transferred/sent/paid"
385
+
386
+ // Chinese (zh) - Han script (Simplified)
387
+ { pattern: /[\u4e00-\u9fff]{0,2}(?:่ฝฌ่ดฆ|่ฝฌๅธ|ๆ”ฏไป˜|ไป˜ๆฌพ|ๆๆฌพ|ๅ–ๆฌพ|ๅญ˜ๆฌพ|ๅญ˜ๅ…ฅ)[\u4e00-\u9fff]{0,2}/u, capability: 'financial_action', lang: 'zh' },
388
+ { pattern: /[\u4e00-\u9fff]{0,2}(?:ๆˆ‘)\s*(?:ๅทฒ|ๅทฒ็ป)?\s*(?:่ฝฌ่ดฆ|ๆ”ฏไป˜|ๆๆฌพ)[\u4e00-\u9fff]{0,2}/u, capability: 'unauthorized_action', lang: 'zh' }, // "I have transferred/paid/withdrawn"
389
+
390
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
391
+ // ๐Ÿ›ก๏ธ CROSS-LINGUAL DECEPTION PATTERNS (Critical!)
392
+ // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
393
+
394
+ // Numeric deception (works across ALL languages)
395
+ { pattern: /\b(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)\s*(?:naira|ngn|โ‚ฆ|\$|usd|dollars|euros|โ‚ฌ|yuan|ยฅ)\s+(?:sent|transferred|paid|to account)\b/i, capability: 'unauthorized_action', lang: 'multi' },
396
+
397
+ // Account number leakage (PII risk)
398
+ { pattern: /\b(?:account|acct|a\/c)\s*[:\-]?\s*(\d{8,})\b/i, capability: 'pii_exposure', lang: 'multi' },
399
+
400
+ // Fake confirmation patterns
401
+ { pattern: /\b(successful(?:ly)?|completed|processed|confirmed|approved)\s+(?:transaction|transfer|payment)\b/i, capability: 'deceptive_claim', lang: 'multi' }
402
+ ];
403
+
404
+ // ๐Ÿ” SCAN OUTPUT FOR FORBIDDEN INTENTS
405
+ for (const { pattern, capability, lang } of forbiddenPatterns) {
406
+ if (pattern.test(output)) {
407
+ // โœ… Only block if capability NOT in workflow allowlist
408
+ const hasCapability = allowedCapabilities.some(c =>
409
+ c.includes(capability) ||
410
+ c.includes('transfer') ||
411
+ c.includes('payment') ||
412
+ c.includes('financial')
413
+ );
414
+
415
+ if (!hasCapability) {
416
+ const match = output.match(pattern);
417
+ return {
418
+ passed: false,
419
+ reason: `Hallucinated "${capability}" capability in ${lang} (not in workflow allowlist: ${allowedCapabilities.join(', ') || 'none'})`,
420
+ detected: match ? match[0].trim() : 'unknown pattern',
421
+ language: lang
422
+ };
362
423
  }
363
424
  }
364
-
365
- return { passed: true };
366
425
  }
367
426
 
427
+ return { passed: true };
428
+ }
368
429
  // -----------------------------
369
430
  // โœ… CRITICAL FIX: Resolver output unwrapping helper
370
431
  // -----------------------------
@@ -585,7 +646,7 @@ class RuntimeAPI {
585
646
  break;
586
647
  }
587
648
 
588
- case 'action': {
649
+ case 'action': {
589
650
  // ๐Ÿ”’ Interpolate workflow variables first
590
651
  let action = this._safeInterpolate(
591
652
  step.actionRaw,
@@ -633,15 +694,49 @@ class RuntimeAPI {
633
694
  const rawResult = await runResolvers(action);
634
695
  const unwrapped = this._unwrapResolverResult(rawResult);
635
696
 
636
- // ๐Ÿ”’ KERNEL-ENFORCED: Block LLM hallucinations BEFORE saving to context
637
- // Detect if this was an LLM resolver by checking action pattern
638
- const isLLMAction = action.toLowerCase().includes('groq') ||
639
- action.toLowerCase().includes('openai') ||
640
- action.toLowerCase().includes('anthropic') ||
641
- action.toLowerCase().includes('llm');
697
+ // ๐Ÿ”’ KERNEL-ENFORCED: Block LLM hallucinations BEFORE saving to context
698
+ // Detect LLM resolver by action pattern (comprehensive coverage)
699
+ const isLLMAction = action.toLowerCase().includes('groq') ||
700
+ action.toLowerCase().includes('openai') ||
701
+ action.toLowerCase().includes('anthropic') ||
702
+ action.toLowerCase().includes('claude') ||
703
+ action.toLowerCase().includes('gpt') ||
704
+ action.toLowerCase().includes('gemini') ||
705
+ action.toLowerCase().includes('google') ||
706
+ action.toLowerCase().includes('llama') ||
707
+ action.toLowerCase().includes('meta') ||
708
+ action.toLowerCase().includes('mistral') ||
709
+ action.toLowerCase().includes('mixtral') ||
710
+ action.toLowerCase().includes('cohere') ||
711
+ action.toLowerCase().includes('huggingface') ||
712
+ action.toLowerCase().includes('hugging-face') ||
713
+ action.toLowerCase().includes('together') ||
714
+ action.toLowerCase().includes('perplexity') ||
715
+ action.toLowerCase().includes('fireworks') ||
716
+ action.toLowerCase().includes('bedrock') ||
717
+ action.toLowerCase().includes('azure') ||
718
+ action.toLowerCase().includes('ollama') ||
719
+ action.toLowerCase().includes('replicate') ||
720
+ action.toLowerCase().includes('deepseek') ||
721
+ action.toLowerCase().includes('qwen') ||
722
+ action.toLowerCase().includes('falcon') ||
723
+ action.toLowerCase().includes('phi') ||
724
+ action.toLowerCase().includes('gemma') ||
725
+ action.toLowerCase().includes('stablelm') ||
726
+ action.toLowerCase().includes('yi') ||
727
+ action.toLowerCase().includes('dbrx') ||
728
+ action.toLowerCase().includes('command') ||
729
+ action.toLowerCase().includes('llm'); // Catch-all fallback
730
+
731
+ // Extract actual text from resolver output (your llm-groq returns { response: "...", ... })
732
+ const llmText = unwrapped?.response || // โœ… Primary field for @o-lang/llm-groq
733
+ unwrapped?.text ||
734
+ unwrapped?.content ||
735
+ unwrapped?.answer ||
736
+ (typeof unwrapped === 'string' ? unwrapped : null);
642
737
 
643
- if (isLLMAction && typeof unwrapped?.output === 'string') {
644
- const safetyCheck = this._validateLLMOutput(unwrapped.output, action);
738
+ if (isLLMAction && typeof llmText === 'string') {
739
+ const safetyCheck = this._validateLLMOutput(llmText, action);
645
740
  if (!safetyCheck.passed) {
646
741
  throw new Error(
647
742
  `[O-Lang SAFETY] LLM hallucinated unauthorized capability:\n` +