@o-lang/olang 1.2.4 ā 1.2.5
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/runtime/RuntimeAPI.js +69 -2
package/package.json
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// src/runtime/RuntimeAPI.js
|
|
2
1
|
const fs = require('fs');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
|
|
@@ -332,6 +331,40 @@ class RuntimeAPI {
|
|
|
332
331
|
});
|
|
333
332
|
}
|
|
334
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
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return { passed: true };
|
|
366
|
+
}
|
|
367
|
+
|
|
335
368
|
// -----------------------------
|
|
336
369
|
// ā
CRITICAL FIX: Resolver output unwrapping helper
|
|
337
370
|
// -----------------------------
|
|
@@ -538,7 +571,7 @@ class RuntimeAPI {
|
|
|
538
571
|
}
|
|
539
572
|
});
|
|
540
573
|
if (!hasDocs) {
|
|
541
|
-
errorMessage += ` ā Visit https://www.npmjs.com/search?q=%40o-lang
|
|
574
|
+
errorMessage += ` ā Visit https://www.npmjs.com/search?q=%40o-lang for resolver packages\n`; // ā
FIXED
|
|
542
575
|
}
|
|
543
576
|
|
|
544
577
|
errorMessage += `\nš Workflow halted to prevent unsafe data propagation to LLMs.`;
|
|
@@ -600,6 +633,26 @@ class RuntimeAPI {
|
|
|
600
633
|
const rawResult = await runResolvers(action);
|
|
601
634
|
const unwrapped = this._unwrapResolverResult(rawResult);
|
|
602
635
|
|
|
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');
|
|
642
|
+
|
|
643
|
+
if (isLLMAction && typeof unwrapped?.output === 'string') {
|
|
644
|
+
const safetyCheck = this._validateLLMOutput(unwrapped.output, action);
|
|
645
|
+
if (!safetyCheck.passed) {
|
|
646
|
+
throw new Error(
|
|
647
|
+
`[O-Lang SAFETY] LLM hallucinated unauthorized capability:\n` +
|
|
648
|
+
` ā Detected: "${safetyCheck.detected}"\n` +
|
|
649
|
+
` ā Reason: ${safetyCheck.reason}\n` +
|
|
650
|
+
` ā Workflow allowlist: ${Array.from(this.allowedResolvers).join(', ')}\n` +
|
|
651
|
+
`\nš Halting to prevent deceptive user experience.`
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
603
656
|
if (step.saveAs) {
|
|
604
657
|
this.context[step.saveAs] = unwrapped;
|
|
605
658
|
}
|
|
@@ -627,6 +680,20 @@ class RuntimeAPI {
|
|
|
627
680
|
const rawResult = await runResolvers(`Action ${target}`);
|
|
628
681
|
const unwrapped = this._unwrapResolverResult(rawResult);
|
|
629
682
|
|
|
683
|
+
// š KERNEL-ENFORCED: Block LLM hallucinations BEFORE saving to context
|
|
684
|
+
if (typeof unwrapped?.output === 'string') {
|
|
685
|
+
const safetyCheck = this._validateLLMOutput(unwrapped.output, target);
|
|
686
|
+
if (!safetyCheck.passed) {
|
|
687
|
+
throw new Error(
|
|
688
|
+
`[O-Lang SAFETY] LLM hallucinated unauthorized capability:\n` +
|
|
689
|
+
` ā Detected: "${safetyCheck.detected}"\n` +
|
|
690
|
+
` ā Reason: ${safetyCheck.reason}\n` +
|
|
691
|
+
` ā Workflow allowlist: ${Array.from(this.allowedResolvers).join(', ')}\n` +
|
|
692
|
+
`\nš Halting to prevent deceptive user experience.`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
630
697
|
if (step.saveAs) this.context[step.saveAs] = unwrapped;
|
|
631
698
|
break;
|
|
632
699
|
}
|