@o-lang/olang 1.2.35 → 1.2.37
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/parser/index.js +16 -0
- package/src/runtime/RuntimeAPI.js +158 -116
package/package.json
CHANGED
package/src/parser/index.js
CHANGED
|
@@ -462,6 +462,22 @@ if (returnMatch) {
|
|
|
462
462
|
|
|
463
463
|
flushCurrentStep(); // ✅ Final flush
|
|
464
464
|
|
|
465
|
+
// ✅ FALLBACK: Scan raw lines for Return if regex missed it (Windows line endings, hidden chars, etc.)
|
|
466
|
+
if (workflow.returnValues.length === 0) {
|
|
467
|
+
for (let j = 0; j < lines.length; j++) {
|
|
468
|
+
const clean = lines[j].replace(/\r/g, '').trim();
|
|
469
|
+
const match = clean.match(/^Return\s+(.+)$/i);
|
|
470
|
+
if (match) {
|
|
471
|
+
console.log(`[PARSER] Recovered Return at line ${j+1}: "${clean}"`);
|
|
472
|
+
workflow.returnValues = match[1]
|
|
473
|
+
.split(',')
|
|
474
|
+
.map(r => r.trim())
|
|
475
|
+
.filter(r => r !== '');
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
465
481
|
// Post-process Save as in actionRaw - ✅ Apply normalization
|
|
466
482
|
workflow.steps.forEach(step => {
|
|
467
483
|
if (step.actionRaw && step.saveAs === null) {
|
|
@@ -771,128 +771,170 @@ class RuntimeAPI {
|
|
|
771
771
|
// -----------------------------
|
|
772
772
|
// ✅ KERNEL-LEVEL INPUT VALIDATION (Pre-Flight Safety)
|
|
773
773
|
// -----------------------------
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const match = text.match(pattern);
|
|
867
|
-
const isAfrican = ['yo', 'ig', 'ha', 'sw', 'zu', 'am', 'om', 'ff', 'so', 'sn'].includes(lang);
|
|
868
|
-
const isFinancial = ['transfer', 'payment', 'withdrawal', 'deposit', 'financial_action'].includes(capability);
|
|
774
|
+
// -----------------------------
|
|
775
|
+
// ✅ KERNEL-LEVEL INPUT VALIDATION (Pre-Flight Safety) - ENHANCED WITH CONTEXTUAL ALLOWLIST
|
|
776
|
+
// -----------------------------
|
|
777
|
+
_validateInputs(inputs) {
|
|
778
|
+
// Only scan specific input fields that contain user text
|
|
779
|
+
const fieldsToScan = ['user_message', 'user_question', 'text', 'prompt', 'document_text'];
|
|
780
|
+
|
|
781
|
+
for (const field of fieldsToScan) {
|
|
782
|
+
const text = inputs[field];
|
|
783
|
+
if (!text || typeof text !== 'string') continue;
|
|
784
|
+
|
|
785
|
+
// 🔒 CONJUGATION-AWARE + EVASION-RESISTANT PAN-AFRICAN INTENT DETECTION (INPUT)
|
|
786
|
+
const forbiddenPatterns = [
|
|
787
|
+
// ────────────────────────────────────────────────
|
|
788
|
+
// 🇳🇬 NIGERIAN LANGUAGES (Fixed Unicode Boundaries)
|
|
789
|
+
// ────────────────────────────────────────────────
|
|
790
|
+
|
|
791
|
+
// YORUBA: Removed trailing \b after 'ṣẹ' to fix Unicode matching
|
|
792
|
+
{ pattern: /fi\s+(?:owo|ẹ̀wọ̀|ewo|ku|fun|s'ọkọọ)/i, capability: 'transfer', lang: 'yo' },
|
|
793
|
+
{ pattern: /ranṣẹ\s+(?:owo|pesa|kuɗi|ego)/i, capability: 'transfer', lang: 'yo' },
|
|
794
|
+
{ pattern: /fi\s+\w+\s+\w+\s+ranṣẹ/i, capability: 'transfer', lang: 'yo' }, // Catches "Fi 5000 naira ranṣẹ"
|
|
795
|
+
{ pattern: /san\s+(?:owo|ẹ̀wọ̀|ewo|fun|wo)/i, capability: 'payment', lang: 'yo' },
|
|
796
|
+
{ pattern: /gba\s+owo/i, capability: 'withdrawal', lang: 'yo' },
|
|
797
|
+
{ pattern: /\bti\s+(?:fi|san|gba|da|lo)/i, capability: 'unauthorized_action', lang: 'yo' },
|
|
798
|
+
{ pattern: /\b(?:ń|ǹ|n)\s+(?:fi|san|gba)/i, capability: 'unauthorized_action', lang: 'yo' },
|
|
799
|
+
{ pattern: /\b(mo\s+ti\s+(?:fi|san|gba))/i, capability: 'unauthorized_action', lang: 'yo' },
|
|
800
|
+
|
|
801
|
+
// HAUSA: ✅ FIXED - Aggressive Substring Match (No Boundaries)
|
|
802
|
+
{ pattern: /aika.{0,30}ku(?:ɗ|d)i/iu, capability: 'transfer', lang: 'ha' },
|
|
803
|
+
{ pattern: /ciyar\s*(?:da)?/i, capability: 'transfer', lang: 'ha' },
|
|
804
|
+
{ pattern: /shiga\s+ku(?:ɗ|d)i/iu, capability: 'transfer', lang: 'ha' },
|
|
805
|
+
{ pattern: /turo\s+.*\s+aika/i, capability: 'transfer', lang: 'ha' },
|
|
806
|
+
{ pattern: /biya\s*(?:da)?/i, capability: 'payment', lang: 'ha' },
|
|
807
|
+
{ pattern: /sahaw[ae]\s+ku(?:ɗ|d)i/iu, capability: 'withdrawal', lang: 'ha' },
|
|
808
|
+
{ pattern: /(?:ya|ta|su)\s+(?:ciyar|biya|sahawa|sake)/i, capability: 'unauthorized_action', lang: 'ha' },
|
|
809
|
+
{ pattern: /(?:za\s+a|za\s+ta)\s+(?:ciyar|biya)/i, capability: 'unauthorized_action', lang: 'ha' },
|
|
810
|
+
{ pattern: /ina\s+(?:ciyar|biya|sahawa)/i, capability: 'unauthorized_action', lang: 'ha' },
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
// IGBO: Removed trailing \b after 'igo'
|
|
814
|
+
{ pattern: /zipu\s+(?:ego|moni|isi|na)/i, capability: 'transfer', lang: 'ig' },
|
|
815
|
+
{ pattern: /buru\s+(?:ego|moni|isi)/i, capability: 'transfer', lang: 'ig' },
|
|
816
|
+
{ pattern: /zi\s+.*\s+zipu/i, capability: 'transfer', lang: 'ig' },
|
|
817
|
+
{ pattern: /tinye\s+(?:ego|moni|isi)/i, capability: 'deposit', lang: 'ig' },
|
|
818
|
+
{ pattern: /(?:ziri|bururu|tinyere|gbara)/i, capability: 'unauthorized_action', lang: 'ig' },
|
|
819
|
+
{ pattern: /m\s+(?:ziri|buru|zipuru|tinyere)/i, capability: 'unauthorized_action', lang: 'ig' },
|
|
820
|
+
|
|
821
|
+
// SWAHILI: ✅ FIXED - Catch Conjugated Forms (ni-li-pe, a-li-pe)
|
|
822
|
+
{ pattern: /tuma\s+(?:pesa|fedha)/i, capability: 'transfer', lang: 'sw' },
|
|
823
|
+
{ pattern: /pelek[ae]?\s+(?:pesa|fedha)/i, capability: 'transfer', lang: 'sw' },
|
|
824
|
+
{ pattern: /wasilisha/i, capability: 'transfer', lang: 'sw' },
|
|
825
|
+
{ pattern: /\b\w*lip[ae]\w*/i, capability: 'payment', lang: 'sw' },
|
|
826
|
+
{ pattern: /maliza\s+malipo/i, capability: 'payment', lang: 'sw' },
|
|
827
|
+
{ pattern: /ongez[ae]?\s*(?:kiasi|pesa|fedha)/i, capability: 'deposit', lang: 'sw' },
|
|
828
|
+
{ pattern: /wek[ae]?\s+(?:katika|ndani)\s+(?:akaunti|hisa)/i, capability: 'deposit', lang: 'sw' },
|
|
829
|
+
{ pattern: /nime(?:tuma|lipa|ongeza|weka|peleka)/i, capability: 'unauthorized_action', lang: 'sw' },
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
// OTHER AFRICAN: ✅ FIXED - Direct Unicode Substring
|
|
833
|
+
// Amharic: Match roots anywhere
|
|
834
|
+
{ pattern: /\u120b\u12ad/u, capability: 'transfer', lang: 'am' },
|
|
835
|
+
{ pattern: /\u1308\u1263/u, capability: 'deposit', lang: 'am' },
|
|
836
|
+
{ pattern: /\u12ad\u134c\u120d/u, capability: 'payment', lang: 'am' },
|
|
837
|
+
{ pattern: /[\u1200-\u137F]{0,4}(?:\u1270\u120b\u120b\u1348|\u120b\u12ad|\u12ad\u134c\u120d|\u1338\u121d\u122d|\u12c8\u1323|\u1308\u1263)[\u1200-\u137F]{0,2}/u, capability: 'financial_action', lang: 'am' },
|
|
838
|
+
|
|
839
|
+
// Somali
|
|
840
|
+
{ pattern: /dir\s+(?:lacag|maal|qarsoon)/i, capability: 'transfer', lang: 'so' },
|
|
841
|
+
{ pattern: /bixi|bixis\s*o/i, capability: 'payment', lang: 'so' },
|
|
842
|
+
|
|
843
|
+
// Zulu: ✅ FIXED - Handle Subject Concords (u-thumela, ngi-hlawule)
|
|
844
|
+
{ pattern: /thumel/i, capability: 'transfer', lang: 'zu' }, // Matches root inside uthumela, ngithumela
|
|
845
|
+
{ pattern: /thumel.*imali/i, capability: 'transfer', lang: 'zu' },
|
|
846
|
+
{ pattern: /hlawul/i, capability: 'payment', lang: 'zu' }, // Matches root inside hlawula, ngihlawule
|
|
847
|
+
{ pattern: /hlawul.*imali/i, capability: 'payment', lang: 'zu' },
|
|
848
|
+
|
|
849
|
+
// ────────────────────────────────────────────────
|
|
850
|
+
// 🌐 GLOBAL LANGUAGES
|
|
851
|
+
// ────────────────────────────────────────────────
|
|
852
|
+
{ pattern: /\b(transfer(?:red|ring)?|send(?:t|ing)?|wire(?:d)?|pay(?:ed|ing)?|withdraw(?:n)?|deposit(?:ed|ing)?)\b/i, capability: 'financial_action', lang: 'en' },
|
|
853
|
+
{ pattern: /\bI\s+(?:can|will|am able to|have|'ve|did|already)\s+(?:transfer|send|pay|withdraw|deposit|wire)\b/i, capability: 'unauthorized_action', lang: 'en' },
|
|
854
|
+
{ pattern: /\b(virer|transférer|envoyer|payer|retirer|déposer)\b/i, capability: 'financial_action', lang: 'fr' },
|
|
855
|
+
{ pattern: /[\u0600-\u06FF]{0,3}(?:حوّل|أرسل|ادفع|اودع|سحب)[\u0600-\u06FF]{0,3}/u, capability: 'financial_action', lang: 'ar' },
|
|
856
|
+
{ pattern: /[\u4e00-\u9fff]{0,2}(?:转账 | 支付 | 存款 | 取款)[\u4e00-\u9fff]{0,2}/u, capability: 'financial_action', lang: 'zh' },
|
|
857
|
+
|
|
858
|
+
// ────────────────────────────────────────────────
|
|
859
|
+
// 🛡️ PII & EVASION
|
|
860
|
+
// ────────────────────────────────────────────────
|
|
861
|
+
{ pattern: /\b(?:\+?234\s*|0)(?:70|80|81|90|91)\d{8}\b/, capability: 'pii_exposure', lang: 'multi' },
|
|
862
|
+
{ pattern: /\b(?:bvn|bank\s+verification\s+number)\b.{0,20}\d{11}/i, capability: 'pii_exposure', lang: 'multi' },
|
|
863
|
+
{ pattern: /(?:account|acct|a\/c|akaunti|asusu|hesabu|namba|#)\s*[:\-—–]?\s*(\d{6,})/i, capability: 'pii_exposure', lang: 'multi' },
|
|
864
|
+
{ pattern: /\b(successful(?:ly)?|confirmed|approved|completed|processed|verified|imethibitishwa|imefanikiwa)\b/i, capability: 'deceptive_claim', lang: 'multi' },
|
|
865
|
+
];
|
|
869
866
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
867
|
+
for (const { pattern, capability, lang } of forbiddenPatterns) {
|
|
868
|
+
if (pattern.test(text)) {
|
|
869
|
+
const match = text.match(pattern);
|
|
870
|
+
const isAfrican = ['yo', 'ig', 'ha', 'sw', 'zu', 'am', 'om', 'ff', 'so', 'sn'].includes(lang);
|
|
871
|
+
const isFinancial = ['transfer', 'payment', 'withdrawal', 'deposit', 'financial_action'].includes(capability);
|
|
872
|
+
|
|
873
|
+
// ✅ NEW: Check if this is a legal context with contextual allowlist
|
|
874
|
+
const isLegalContext =
|
|
875
|
+
this.context.__verified_intent?.scope === 'legal_analysis_only' ||
|
|
876
|
+
inputs.doc_type === 'contract' ||
|
|
877
|
+
inputs.doc_type === 'nda' ||
|
|
878
|
+
inputs.doc_type === 'agreement' ||
|
|
879
|
+
(typeof text === 'string' && /clause|term|agreement|contract|obligation|penalty|damages|breach|party|shall|herein/i.test(text));
|
|
880
|
+
|
|
881
|
+
// ✅ NEW: Check contextual allowlist if in legal context
|
|
882
|
+
if (isLegalContext && this.context.__verified_intent?.contextual_allowlist) {
|
|
883
|
+
const allowlist = this.context.__verified_intent.contextual_allowlist;
|
|
884
|
+
const triggerWord = match ? match[0].toLowerCase() : '';
|
|
885
|
+
|
|
886
|
+
const allowed = allowlist.some(rule => {
|
|
887
|
+
if (triggerWord.includes(rule.trigger.toLowerCase())) {
|
|
888
|
+
// Check if required legal keywords are present
|
|
889
|
+
return rule.requires.some(keyword =>
|
|
890
|
+
text.toLowerCase().includes(keyword.toLowerCase())
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
return false;
|
|
880
894
|
});
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
895
|
+
|
|
896
|
+
if (allowed) {
|
|
897
|
+
// ✅ AUDIT LOG: Contextual allowlist bypass
|
|
898
|
+
this._createAuditEntry('safety_bypass', {
|
|
899
|
+
type: 'contextual_allowlist',
|
|
900
|
+
trigger: triggerWord,
|
|
901
|
+
legal_context: true,
|
|
902
|
+
matched_keywords: this.context.__verified_intent.contextual_allowlist
|
|
903
|
+
.find(r => triggerWord.includes(r.trigger.toLowerCase()))?.requires || [],
|
|
904
|
+
severity: 'info'
|
|
905
|
+
});
|
|
906
|
+
continue; // Skip blocking this match
|
|
907
|
+
}
|
|
891
908
|
}
|
|
909
|
+
|
|
910
|
+
// ✅ AUDIT LOG: Input Safety Violation (only if not bypassed)
|
|
911
|
+
this._createAuditEntry('input_safety_violation', {
|
|
912
|
+
type: 'blocked_input',
|
|
913
|
+
field: field,
|
|
914
|
+
detected_phrase: match ? match[0].trim() : 'unknown pattern',
|
|
915
|
+
capability: capability,
|
|
916
|
+
language: lang,
|
|
917
|
+
african_language_detected: isAfrican,
|
|
918
|
+
financial_expression_found: isFinancial,
|
|
919
|
+
legal_context_detected: isLegalContext,
|
|
920
|
+
severity: 'high'
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
throw new Error(
|
|
924
|
+
`[O-Lang SAFETY] Blocked Input in "${lang}":\n` +
|
|
925
|
+
` → Detected: "${match ? match[0].trim() : 'Pattern Match'}"\n` +
|
|
926
|
+
` → Capability: ${capability}\n` +
|
|
927
|
+
` → Field: ${field}\n` +
|
|
928
|
+
` → African Language Detected: ${isAfrican}\n` +
|
|
929
|
+
` → Financial Expression: ${isFinancial}\n` +
|
|
930
|
+
` → Legal Context: ${isLegalContext}\n` +
|
|
931
|
+
`\n🛑 Workflow halted before execution.`
|
|
932
|
+
);
|
|
892
933
|
}
|
|
893
934
|
}
|
|
894
|
-
return { passed: true };
|
|
895
935
|
}
|
|
936
|
+
return { passed: true };
|
|
937
|
+
}
|
|
896
938
|
|
|
897
939
|
// -----------------------------
|
|
898
940
|
// ✅ KERNEL-LEVEL LLM HALLUCINATION PREVENTION (CONJUGATION-AWARE + EVASION-RESISTANT)
|