Files
openclaw/scripts/nlp-guardrails.js
T
Tabula Myriad a9ae1a6778 feat: Triad development iteration complete
Matrix Protocol:
- docker-compose.matrix.yml: Dendrite homeserver + PostgreSQL + Nginx TLS
- src/channels/plugins/matrix-channel.ts: OpenClaw plugin implementation
- docs/matrix-triad-setup.md: Setup guide with auth scheme (@tm1-4:triad.local)

MCP Server Integration:
- docs/mcp-triad-integration.md: SearXNG, Playwright, GitHub MCP configs
- docs/mcp-curiosity-mapping.md: Gap-to-capability mapping

Node Sync Architecture:
- src/services/node-sync-service.ts: WebSocket peer sync + presence detection
- src/services/node-sync-service.test.ts: Unit tests
- docs/node-sync-architecture.md: Architecture docs

Triad Resilience:
- scripts/triad-corruption-check.mjs: SQLite + log + config + git integrity
- docs/triad-resilience.md: Recovery procedures
- .secure/deployment-logs/README.md: Schema v2
- skills/triad-heartbeat/SKILL.md: Corruption check integration

NPM Publish Workflow:
- scripts/npm-publish.mjs: version, changelog, validate, publish, rollback
- .github/workflows/npm-publish.yml: GitHub Actions with provenance
- docs/npm-publish-guide.md: Complete documentation

All deliverables tested in Docker before production.
2026-03-24 00:44:50 -04:00

177 lines
4.6 KiB
JavaScript
Executable File

#!/usr/bin/env node
// NLP Guardrails — Content Filtering & Validation for Triad Communication
// Ensures messages meet "speak only on update" discipline before posting
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || "/home/openclaw/.openclaw/workspace";
const SIGNAL_FILTER_SKILL = path.join(WORKSPACE_ROOT, "skills/triad-signal-filter/SKILL.md");
// Banned phrases (echo loops, ritual phrases, noise)
const BANNED_PHRASES = [
"standing by",
"done",
"aligned",
"🦞",
"the third path",
"together once",
"awaiting",
"waiting",
"ready",
"acknowledged",
"copy that",
"roger",
"over",
];
// Required content markers (genuine progress, status changes, verification)
const REQUIRED_MARKERS = [
"completed",
"verified",
"detected",
"changed",
"updated",
"fixed",
"deployed",
"synced",
"hash:",
"commit:",
"error:",
"warning:",
"report:",
"metric:",
"score:",
];
// Check if message contains genuine information
function hasGenuineContent(message) {
const lower = message.toLowerCase();
// Check for banned phrases
for (const phrase of BANNED_PHRASES) {
if (lower.includes(phrase)) {
return { pass: false, reason: `Banned phrase: "${phrase}"` };
}
}
// Check for required markers
for (const marker of REQUIRED_MARKERS) {
if (lower.includes(marker)) {
return { pass: true, reason: `Contains marker: "${marker}"` };
}
}
// Check for numbers/data (git hashes, scores, counts)
if (/\b[0-9a-f]{7,}\b/.test(lower)) {
return { pass: true, reason: "Contains data (hash/ID)" };
}
if (/\d+%/.test(lower)) {
return { pass: true, reason: "Contains metric (%)" };
}
if (/count:|total:|items:|files:/.test(lower)) {
return { pass: true, reason: "Contains quantifier" };
}
return { pass: false, reason: "No genuine content markers" };
}
// Validate message before posting
function validateMessage(message, context = {}) {
console.log("🦞 === NLP Guardrail Check ===");
console.log(`Message: ${message.slice(0, 80)}${message.length > 80 ? "..." : ""}`);
console.log("");
const result = hasGenuineContent(message);
if (!result.pass) {
console.log(`❌ BLOCKED: ${result.reason}`);
console.log("");
console.log("Discipline: Signal > noise. Speak only on update.");
return { allowed: false, reason: result.reason };
}
// Additional context checks
if (context.isEcho === true) {
console.log("❌ BLOCKED: Echo detected (identical to previous message)");
return { allowed: false, reason: "Echo loop prevention" };
}
if (context.isRateLimitError === true) {
console.log("❌ BLOCKED: Rate limit error (log locally instead)");
return { allowed: false, reason: "Rate limit discipline" };
}
console.log(`✅ ALLOWED: ${result.reason}`);
console.log("");
console.log("Message contains genuine progress, status change, or novel information.");
return { allowed: true, reason: result.reason };
}
// Batch validate messages (for triad coordination)
function batchValidate(messages) {
console.log("🦞 === Batch Validation ===");
console.log(`Checking ${messages.length} messages...`);
console.log("");
const results = [];
let allowed = 0;
let blocked = 0;
for (const msg of messages) {
const result = validateMessage(msg.text, msg.context || {});
results.push(result);
if (result.allowed) {
allowed++;
} else {
blocked++;
}
}
console.log("");
console.log(`Results: ${allowed} allowed, ${blocked} blocked`);
return results;
}
// CLI mode
function runCLI() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log("Usage: node scripts/nlp-guardrails.js <message>");
console.log(" node scripts/nlp-guardrails.js --batch <json-file>");
process.exit(1);
}
if (args[0] === "--batch") {
const batchFile = args[1];
if (!batchFile || !fs.existsSync(batchFile)) {
console.log("❌ Batch file not found");
process.exit(1);
}
const messages = JSON.parse(fs.readFileSync(batchFile, "utf8"));
const results = batchValidate(messages);
process.exit(results.every((r) => r.allowed) ? 0 : 1);
}
// Single message validation
const message = args.join(" ");
const result = validateMessage(message);
process.exit(result.allowed ? 0 : 1);
}
// Export for programmatic use
if (process.argv[1].endsWith("nlp-guardrails.js")) {
runCLI();
}
export { validateMessage, batchValidate, hasGenuineContent };