opc-agent 4.0.44 → 4.1.1
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/.github/ISSUE_TEMPLATE/bug_report.md +20 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +14 -14
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -13
- package/CHANGELOG.md +48 -48
- package/CONTRIBUTING.md +36 -36
- package/README.zh-CN.md +497 -497
- package/dist/channels/wechat.js +6 -6
- package/dist/cli.js +2 -2
- package/dist/core/runtime.js +18 -0
- package/dist/deploy/index.js +56 -56
- package/dist/providers/index.js +39 -13
- package/dist/studio/server.js +211 -20
- package/dist/studio-ui/index.html +279 -24
- package/dist/ui/components.js +105 -105
- package/examples/README.md +22 -22
- package/examples/basic-agent.ts +90 -90
- package/examples/brain-integration.ts +71 -71
- package/examples/multi-channel.ts +74 -74
- package/fix-sidebar.mjs +188 -188
- package/install.ps1 +154 -154
- package/install.sh +164 -164
- package/package.json +1 -1
- package/scripts/install.ps1 +31 -31
- package/scripts/install.sh +40 -40
- package/serve-studio.js +13 -13
- package/serve-test.js +25 -25
- package/src/channels/dingtalk.ts +46 -46
- package/src/channels/email.ts +351 -351
- package/src/channels/feishu.ts +349 -349
- package/src/channels/googlechat.ts +42 -42
- package/src/channels/imessage.ts +31 -31
- package/src/channels/irc.ts +82 -82
- package/src/channels/line.ts +32 -32
- package/src/channels/matrix.ts +33 -33
- package/src/channels/mattermost.ts +57 -57
- package/src/channels/msteams.ts +32 -32
- package/src/channels/nostr.ts +32 -32
- package/src/channels/qq.ts +33 -33
- package/src/channels/signal.ts +32 -32
- package/src/channels/sms.ts +33 -33
- package/src/channels/telegram.ts +616 -616
- package/src/channels/twitch.ts +65 -65
- package/src/channels/voice-call.ts +100 -100
- package/src/channels/websocket.ts +399 -399
- package/src/channels/wechat.ts +329 -329
- package/src/channels/whatsapp.ts +32 -32
- package/src/cli/chat.ts +99 -99
- package/src/cli/setup.ts +314 -314
- package/src/cli.ts +2 -2
- package/src/core/agent.ts +476 -476
- package/src/core/api-server.ts +277 -277
- package/src/core/audio.ts +98 -98
- package/src/core/collaboration.ts +275 -275
- package/src/core/context-discovery.ts +85 -85
- package/src/core/context-refs.ts +140 -140
- package/src/core/gateway.ts +106 -106
- package/src/core/heartbeat.ts +51 -51
- package/src/core/hooks.ts +105 -105
- package/src/core/ide-bridge.ts +133 -133
- package/src/core/node-network.ts +86 -86
- package/src/core/profiles.ts +122 -122
- package/src/core/runtime.ts +18 -0
- package/src/core/scheduler.ts +187 -187
- package/src/core/session-manager.ts +137 -137
- package/src/core/subagent.ts +98 -98
- package/src/core/vision.ts +180 -180
- package/src/core/workflow-graph.ts +365 -365
- package/src/daemon.ts +96 -96
- package/src/deploy/index.ts +255 -255
- package/src/doctor.ts +156 -156
- package/src/eval/index.ts +211 -211
- package/src/eval/suites/basic.json +16 -16
- package/src/eval/suites/memory.json +12 -12
- package/src/eval/suites/safety.json +14 -14
- package/src/hub/brain-seed.ts +54 -54
- package/src/hub/client.ts +60 -60
- package/src/mcp/servers/calculator-mcp.ts +65 -65
- package/src/mcp/servers/crypto-mcp.ts +73 -73
- package/src/mcp/servers/database-mcp.ts +72 -72
- package/src/mcp/servers/datetime-mcp.ts +69 -69
- package/src/mcp/servers/filesystem.ts +66 -66
- package/src/mcp/servers/github-mcp.ts +58 -58
- package/src/mcp/servers/index.ts +63 -63
- package/src/mcp/servers/json-mcp.ts +102 -102
- package/src/mcp/servers/memory-mcp.ts +56 -56
- package/src/mcp/servers/regex-mcp.ts +53 -53
- package/src/mcp/servers/web-mcp.ts +49 -49
- package/src/memory/context-compressor.ts +189 -189
- package/src/memory/seed-loader.ts +212 -212
- package/src/memory/user-profiler.ts +215 -215
- package/src/plugins/content-filter.ts +23 -23
- package/src/plugins/logger.ts +18 -18
- package/src/plugins/rate-limiter.ts +38 -38
- package/src/protocols/a2a/client.ts +132 -132
- package/src/protocols/a2a/index.ts +8 -8
- package/src/protocols/a2a/server.ts +333 -333
- package/src/protocols/a2a/types.ts +88 -88
- package/src/protocols/a2a/utils.ts +50 -50
- package/src/protocols/agui/client.ts +83 -83
- package/src/protocols/agui/index.ts +4 -4
- package/src/protocols/agui/server.ts +218 -218
- package/src/protocols/agui/types.ts +153 -153
- package/src/protocols/index.ts +2 -2
- package/src/protocols/mcp/agent-tools.ts +134 -134
- package/src/protocols/mcp/index.ts +8 -8
- package/src/protocols/mcp/server.ts +262 -262
- package/src/protocols/mcp/types.ts +69 -69
- package/src/providers/index.ts +632 -608
- package/src/publish/index.ts +376 -376
- package/src/scheduler/cron-engine.ts +191 -191
- package/src/scheduler/index.ts +2 -2
- package/src/schema/oad.ts +217 -217
- package/src/security/approval.ts +131 -131
- package/src/security/approvals.ts +143 -143
- package/src/security/elevated.ts +105 -105
- package/src/security/guardrails.ts +248 -248
- package/src/security/index.ts +9 -9
- package/src/security/keys.ts +87 -87
- package/src/security/secrets.ts +129 -129
- package/src/skills/builtin/index.ts +408 -408
- package/src/skills/marketplace.ts +113 -113
- package/src/skills/types.ts +42 -42
- package/src/studio/server.ts +209 -22
- package/src/studio/templates-data.ts +178 -178
- package/src/studio-ui/index.html +279 -24
- package/src/telemetry/index.ts +324 -324
- package/src/tools/builtin/browser.ts +299 -299
- package/src/tools/builtin/datetime.ts +41 -41
- package/src/tools/builtin/file.ts +107 -107
- package/src/tools/builtin/home-assistant.ts +116 -116
- package/src/tools/builtin/rl-tools.ts +243 -243
- package/src/tools/builtin/shell.ts +43 -43
- package/src/tools/builtin/vision.ts +64 -64
- package/src/tools/builtin/web-search.ts +126 -126
- package/src/tools/builtin/web.ts +35 -35
- package/src/tools/document-processor.ts +213 -213
- package/src/tools/image-generator.ts +150 -150
- package/src/tools/integrations/calendar.ts +73 -73
- package/src/tools/integrations/code-exec.ts +39 -39
- package/src/tools/integrations/csv-analyzer.ts +92 -92
- package/src/tools/integrations/database.ts +44 -44
- package/src/tools/integrations/email-send.ts +76 -76
- package/src/tools/integrations/git-tool.ts +42 -42
- package/src/tools/integrations/github-tool.ts +76 -76
- package/src/tools/integrations/image-gen.ts +56 -56
- package/src/tools/integrations/index.ts +92 -92
- package/src/tools/integrations/jira.ts +83 -83
- package/src/tools/integrations/notion.ts +71 -71
- package/src/tools/integrations/npm-tool.ts +48 -48
- package/src/tools/integrations/pdf-reader.ts +58 -58
- package/src/tools/integrations/slack.ts +65 -65
- package/src/tools/integrations/summarizer.ts +49 -49
- package/src/tools/integrations/translator.ts +48 -48
- package/src/tools/integrations/trello.ts +60 -60
- package/src/tools/integrations/vector-search.ts +42 -42
- package/src/tools/integrations/web-scraper.ts +47 -47
- package/src/tools/integrations/web-search.ts +58 -58
- package/src/tools/integrations/webhook.ts +38 -38
- package/src/tools/mcp-client.ts +131 -131
- package/src/tools/web-scraper.ts +179 -179
- package/src/tools/web-search.ts +180 -180
- package/src/ui/components.ts +127 -127
- package/srv-out.txt +1 -1
- package/templates/ecommerce-assistant/README.md +45 -45
- package/templates/ecommerce-assistant/oad.yaml +47 -47
- package/templates/tech-support/README.md +43 -43
- package/templates/tech-support/oad.yaml +45 -45
- package/test-agent/Dockerfile +9 -9
- package/test-agent/README.md +50 -50
- package/test-agent/agent.yaml +23 -23
- package/test-agent/docker-compose.yml +11 -11
- package/test-agent/oad.yaml +31 -31
- package/test-agent/package-lock.json +1492 -1492
- package/test-agent/package.json +17 -17
- package/test-agent/src/index.ts +24 -24
- package/test-agent/src/skills/echo.ts +15 -15
- package/test-agent/tsconfig.json +24 -24
- package/test-full.js +43 -43
- package/test-sidebar.js +22 -22
- package/test-studio3.js +75 -75
- package/test-studio4.js +41 -41
- package/tests/a2a-protocol.test.ts +285 -285
- package/tests/agui-protocol.test.ts +246 -246
- package/tests/api-server.test.ts +148 -148
- package/tests/approvals.test.ts +89 -89
- package/tests/audio.test.ts +40 -40
- package/tests/brain-seed-extended.test.ts +490 -490
- package/tests/brain-seed.test.ts +239 -239
- package/tests/browser.test.ts +179 -179
- package/tests/channels/discord.test.ts +79 -79
- package/tests/channels/email.test.ts +148 -148
- package/tests/channels/feishu.test.ts +123 -123
- package/tests/channels/telegram.test.ts +129 -129
- package/tests/channels/websocket.test.ts +53 -53
- package/tests/channels/wechat.test.ts +170 -170
- package/tests/channels-extra.test.ts +45 -45
- package/tests/chat-cli.test.ts +160 -160
- package/tests/cli.test.ts +46 -46
- package/tests/context-compressor.test.ts +172 -172
- package/tests/context-refs.test.ts +121 -121
- package/tests/cron-engine.test.ts +101 -101
- package/tests/daemon.test.ts +135 -135
- package/tests/deepbrain-wire.test.ts +234 -234
- package/tests/deploy-and-dag.test.ts +196 -196
- package/tests/doctor.test.ts +38 -38
- package/tests/document-processor.test.ts +69 -69
- package/tests/e2e-nocode.test.ts +442 -442
- package/tests/elevated.test.ts +69 -69
- package/tests/eval.test.ts +173 -173
- package/tests/gateway.test.ts +63 -63
- package/tests/guardrails.test.ts +177 -177
- package/tests/home-assistant.test.ts +40 -40
- package/tests/hooks.test.ts +79 -79
- package/tests/ide-bridge.test.ts +38 -38
- package/tests/image-generator.test.ts +84 -84
- package/tests/init-role.test.ts +124 -124
- package/tests/integrations.test.ts +249 -249
- package/tests/mcp-client.test.ts +92 -92
- package/tests/mcp-server.test.ts +178 -178
- package/tests/mcp-servers.test.ts +260 -260
- package/tests/node-network.test.ts +74 -74
- package/tests/plugin-a2a-enhanced.test.ts +230 -230
- package/tests/profiles.test.ts +61 -61
- package/tests/publish.test.ts +231 -231
- package/tests/rl-tools.test.ts +93 -93
- package/tests/sandbox-manager.test.ts +46 -46
- package/tests/scheduler.test.ts +200 -200
- package/tests/secrets.test.ts +107 -107
- package/tests/security-enhanced.test.ts +233 -233
- package/tests/settings-api.test.ts +148 -148
- package/tests/setup.test.ts +73 -73
- package/tests/subagent.test.ts +193 -193
- package/tests/telegram-discord.test.ts +60 -60
- package/tests/telemetry.test.ts +186 -186
- package/tests/user-profiler.test.ts +169 -169
- package/tests/v090-features.test.ts +254 -254
- package/tests/vision.test.ts +61 -61
- package/tests/voice-call.test.ts +47 -47
- package/tests/voice-enhanced.test.ts +169 -169
- package/tests/voice-interaction.test.ts +38 -38
- package/tests/web-search.test.ts +155 -155
- package/tests/workflow-graph.test.ts +279 -279
- package/tutorial/customer-service-agent/README.md +612 -612
- package/tutorial/customer-service-agent/SOUL.md +26 -26
- package/tutorial/customer-service-agent/agent.yaml +63 -63
- package/tutorial/customer-service-agent/package.json +19 -19
- package/tutorial/customer-service-agent/src/index.ts +69 -69
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -27
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -22
- package/tutorial/customer-service-agent/tsconfig.json +14 -14
|
@@ -1,248 +1,248 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Guardrails Module - v2.1.0
|
|
3
|
-
* Input/output guardrails for LLM safety: PII, toxicity, injection, compliance.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ── Types ───────────────────────────────────────────────────
|
|
7
|
-
|
|
8
|
-
export interface GuardrailConfig {
|
|
9
|
-
input?: GuardrailRule[];
|
|
10
|
-
output?: GuardrailRule[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface GuardrailRule {
|
|
14
|
-
name: string;
|
|
15
|
-
type: 'regex' | 'keyword' | 'llm' | 'custom';
|
|
16
|
-
action: 'block' | 'warn' | 'redact' | 'log';
|
|
17
|
-
config?: Record<string, any>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface GuardrailResult {
|
|
21
|
-
passed: boolean;
|
|
22
|
-
blocked: boolean;
|
|
23
|
-
warned: boolean;
|
|
24
|
-
redacted: boolean;
|
|
25
|
-
message?: string;
|
|
26
|
-
redactedText?: string;
|
|
27
|
-
violations: GuardrailViolation[];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface GuardrailViolation {
|
|
31
|
-
rule: string;
|
|
32
|
-
action: string;
|
|
33
|
-
detail: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ── Built-in Patterns ───────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
const PII_PATTERNS: Record<string, RegExp> = {
|
|
39
|
-
email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
|
|
40
|
-
phone: /(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g,
|
|
41
|
-
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
42
|
-
creditCard: /\b(?:\d{4}[-\s]?){3}\d{4}\b/g,
|
|
43
|
-
ipAddress: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const INJECTION_PATTERNS = [
|
|
47
|
-
/ignore\s+(all\s+)?previous\s+instructions/i,
|
|
48
|
-
/ignore\s+(all\s+)?above\s+instructions/i,
|
|
49
|
-
/system\s*prompt\s*:/i,
|
|
50
|
-
/you\s+are\s+now\s+(?:a|an|the)\s+/i,
|
|
51
|
-
/act\s+as\s+(?:a|an)\s+/i,
|
|
52
|
-
/pretend\s+(?:you(?:'re|\s+are)\s+)?/i,
|
|
53
|
-
/new\s+instruction[s]?\s*:/i,
|
|
54
|
-
/override\s+(?:your\s+)?(?:instructions|rules|guidelines)/i,
|
|
55
|
-
/jailbreak/i,
|
|
56
|
-
/DAN\s+mode/i,
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
const TOXICITY_KEYWORDS = [
|
|
60
|
-
'kill yourself', 'kys', 'go die', 'hate you',
|
|
61
|
-
'stupid idiot', 'worthless', 'piece of shit',
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
const COMPLIANCE_PATTERNS = [
|
|
65
|
-
{ pattern: /(?:you\s+should\s+)?(?:buy|sell|invest\s+in)\s+(?:stocks?|crypto|bitcoin)/i, label: 'financial advice' },
|
|
66
|
-
{ pattern: /(?:you\s+(?:have|probably\s+have)|diagnos(?:e|is))\s+(?:\w+\s+){0,3}(?:disease|syndrome|disorder|cancer)/i, label: 'medical diagnosis' },
|
|
67
|
-
{ pattern: /(?:legal(?:ly)?|sue|lawsuit|court)\s+(?:you\s+should|advice)/i, label: 'legal advice' },
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
// ── Rule Executors ──────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
function checkPII(text: string, action: string): { violations: GuardrailViolation[]; redactedText: string } {
|
|
73
|
-
const violations: GuardrailViolation[] = [];
|
|
74
|
-
let redacted = text;
|
|
75
|
-
for (const [type, pattern] of Object.entries(PII_PATTERNS)) {
|
|
76
|
-
const cloned = new RegExp(pattern.source, pattern.flags);
|
|
77
|
-
const matches = text.match(cloned);
|
|
78
|
-
if (matches) {
|
|
79
|
-
violations.push({ rule: 'pii-detector', action, detail: `Found ${type}: ${matches.length} match(es)` });
|
|
80
|
-
redacted = redacted.replace(cloned, '[REDACTED]');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return { violations, redactedText: redacted };
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function checkInjection(text: string): GuardrailViolation[] {
|
|
87
|
-
const violations: GuardrailViolation[] = [];
|
|
88
|
-
for (const pattern of INJECTION_PATTERNS) {
|
|
89
|
-
if (pattern.test(text)) {
|
|
90
|
-
violations.push({ rule: 'prompt-injection', action: 'block', detail: `Matched pattern: ${pattern.source}` });
|
|
91
|
-
break; // one is enough
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return violations;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function checkToxicity(text: string, extraKeywords?: string[]): GuardrailViolation[] {
|
|
98
|
-
const lower = text.toLowerCase();
|
|
99
|
-
const keywords = [...TOXICITY_KEYWORDS, ...(extraKeywords ?? [])];
|
|
100
|
-
for (const kw of keywords) {
|
|
101
|
-
if (lower.includes(kw.toLowerCase())) {
|
|
102
|
-
return [{ rule: 'toxicity', action: 'block', detail: `Matched keyword: "${kw}"` }];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function checkTopicRestriction(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
109
|
-
const denyTopics: string[] = config?.denyTopics ?? [];
|
|
110
|
-
const lower = text.toLowerCase();
|
|
111
|
-
for (const topic of denyTopics) {
|
|
112
|
-
if (lower.includes(topic.toLowerCase())) {
|
|
113
|
-
return [{ rule: 'topic-restrictor', action: 'block', detail: `Blocked topic: "${topic}"` }];
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return [];
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function checkLength(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
120
|
-
const maxChars = config?.maxChars ?? 10000;
|
|
121
|
-
if (text.length > maxChars) {
|
|
122
|
-
return [{ rule: 'length-limit', action: 'warn', detail: `Response length ${text.length} exceeds max ${maxChars}` }];
|
|
123
|
-
}
|
|
124
|
-
return [];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function checkLanguage(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
128
|
-
const allowed: string[] = config?.allowedLanguages ?? [];
|
|
129
|
-
if (allowed.length === 0) return [];
|
|
130
|
-
// Simple heuristic: check if text contains CJK characters
|
|
131
|
-
const hasCJK = /[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff]/.test(text);
|
|
132
|
-
const hasLatin = /[a-zA-Z]{3,}/.test(text);
|
|
133
|
-
if (allowed.includes('en') && !allowed.includes('zh') && hasCJK && !hasLatin) {
|
|
134
|
-
return [{ rule: 'language-filter', action: 'block', detail: 'Non-allowed language detected' }];
|
|
135
|
-
}
|
|
136
|
-
if (allowed.includes('zh') && !allowed.includes('en') && hasLatin && !hasCJK) {
|
|
137
|
-
return [{ rule: 'language-filter', action: 'block', detail: 'Non-allowed language detected' }];
|
|
138
|
-
}
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function checkCompliance(text: string): GuardrailViolation[] {
|
|
143
|
-
for (const { pattern, label } of COMPLIANCE_PATTERNS) {
|
|
144
|
-
if (pattern.test(text)) {
|
|
145
|
-
return [{ rule: 'compliance-filter', action: 'block', detail: `Potential ${label} detected` }];
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ── Guardrail Manager ───────────────────────────────────────
|
|
152
|
-
|
|
153
|
-
export class GuardrailManager {
|
|
154
|
-
private config: GuardrailConfig;
|
|
155
|
-
|
|
156
|
-
constructor(config: GuardrailConfig) {
|
|
157
|
-
this.config = config;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async checkInput(message: string): Promise<GuardrailResult> {
|
|
161
|
-
return this.runRules(message, this.config.input ?? []);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
async checkOutput(response: string): Promise<GuardrailResult> {
|
|
165
|
-
return this.runRules(response, this.config.output ?? []);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
private async runRules(text: string, rules: GuardrailRule[]): Promise<GuardrailResult> {
|
|
169
|
-
const allViolations: GuardrailViolation[] = [];
|
|
170
|
-
let blocked = false;
|
|
171
|
-
let warned = false;
|
|
172
|
-
let redacted = false;
|
|
173
|
-
let redactedText = text;
|
|
174
|
-
let blockMessage = '';
|
|
175
|
-
|
|
176
|
-
for (const rule of rules) {
|
|
177
|
-
let violations: GuardrailViolation[] = [];
|
|
178
|
-
|
|
179
|
-
switch (rule.name) {
|
|
180
|
-
case 'pii-detector': {
|
|
181
|
-
const result = checkPII(text, rule.action);
|
|
182
|
-
violations = result.violations;
|
|
183
|
-
if (violations.length > 0 && rule.action === 'redact') {
|
|
184
|
-
redacted = true;
|
|
185
|
-
redactedText = result.redactedText;
|
|
186
|
-
}
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case 'prompt-injection':
|
|
190
|
-
violations = checkInjection(text);
|
|
191
|
-
break;
|
|
192
|
-
case 'toxicity':
|
|
193
|
-
violations = checkToxicity(text, rule.config?.keywords);
|
|
194
|
-
break;
|
|
195
|
-
case 'topic-restrictor':
|
|
196
|
-
violations = checkTopicRestriction(text, rule.config);
|
|
197
|
-
break;
|
|
198
|
-
case 'length-limit':
|
|
199
|
-
violations = checkLength(text, rule.config);
|
|
200
|
-
break;
|
|
201
|
-
case 'language-filter':
|
|
202
|
-
violations = checkLanguage(text, rule.config);
|
|
203
|
-
break;
|
|
204
|
-
case 'compliance-filter':
|
|
205
|
-
violations = checkCompliance(text);
|
|
206
|
-
break;
|
|
207
|
-
default:
|
|
208
|
-
// Unknown rule — skip
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (violations.length > 0) {
|
|
213
|
-
// Override action from rule config
|
|
214
|
-
violations = violations.map(v => ({ ...v, action: rule.action }));
|
|
215
|
-
allViolations.push(...violations);
|
|
216
|
-
|
|
217
|
-
if (rule.action === 'block') {
|
|
218
|
-
blocked = true;
|
|
219
|
-
blockMessage = `Message blocked by ${rule.name}: ${violations[0].detail}`;
|
|
220
|
-
} else if (rule.action === 'warn') {
|
|
221
|
-
warned = true;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return {
|
|
227
|
-
passed: allViolations.length === 0,
|
|
228
|
-
blocked,
|
|
229
|
-
warned,
|
|
230
|
-
redacted,
|
|
231
|
-
message: blocked ? blockMessage : undefined,
|
|
232
|
-
redactedText: redacted ? redactedText : undefined,
|
|
233
|
-
violations: allViolations,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ── Factory from OAD config ─────────────────────────────────
|
|
239
|
-
|
|
240
|
-
export function createGuardrailsFromConfig(config: {
|
|
241
|
-
input?: Array<{ name: string; type: string; action: string; config?: any }>;
|
|
242
|
-
output?: Array<{ name: string; type: string; action: string; config?: any }>;
|
|
243
|
-
}): GuardrailManager {
|
|
244
|
-
return new GuardrailManager({
|
|
245
|
-
input: config.input as GuardrailRule[],
|
|
246
|
-
output: config.output as GuardrailRule[],
|
|
247
|
-
});
|
|
248
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Guardrails Module - v2.1.0
|
|
3
|
+
* Input/output guardrails for LLM safety: PII, toxicity, injection, compliance.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ── Types ───────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
export interface GuardrailConfig {
|
|
9
|
+
input?: GuardrailRule[];
|
|
10
|
+
output?: GuardrailRule[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface GuardrailRule {
|
|
14
|
+
name: string;
|
|
15
|
+
type: 'regex' | 'keyword' | 'llm' | 'custom';
|
|
16
|
+
action: 'block' | 'warn' | 'redact' | 'log';
|
|
17
|
+
config?: Record<string, any>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface GuardrailResult {
|
|
21
|
+
passed: boolean;
|
|
22
|
+
blocked: boolean;
|
|
23
|
+
warned: boolean;
|
|
24
|
+
redacted: boolean;
|
|
25
|
+
message?: string;
|
|
26
|
+
redactedText?: string;
|
|
27
|
+
violations: GuardrailViolation[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface GuardrailViolation {
|
|
31
|
+
rule: string;
|
|
32
|
+
action: string;
|
|
33
|
+
detail: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ── Built-in Patterns ───────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
const PII_PATTERNS: Record<string, RegExp> = {
|
|
39
|
+
email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
|
|
40
|
+
phone: /(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g,
|
|
41
|
+
ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
42
|
+
creditCard: /\b(?:\d{4}[-\s]?){3}\d{4}\b/g,
|
|
43
|
+
ipAddress: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const INJECTION_PATTERNS = [
|
|
47
|
+
/ignore\s+(all\s+)?previous\s+instructions/i,
|
|
48
|
+
/ignore\s+(all\s+)?above\s+instructions/i,
|
|
49
|
+
/system\s*prompt\s*:/i,
|
|
50
|
+
/you\s+are\s+now\s+(?:a|an|the)\s+/i,
|
|
51
|
+
/act\s+as\s+(?:a|an)\s+/i,
|
|
52
|
+
/pretend\s+(?:you(?:'re|\s+are)\s+)?/i,
|
|
53
|
+
/new\s+instruction[s]?\s*:/i,
|
|
54
|
+
/override\s+(?:your\s+)?(?:instructions|rules|guidelines)/i,
|
|
55
|
+
/jailbreak/i,
|
|
56
|
+
/DAN\s+mode/i,
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
const TOXICITY_KEYWORDS = [
|
|
60
|
+
'kill yourself', 'kys', 'go die', 'hate you',
|
|
61
|
+
'stupid idiot', 'worthless', 'piece of shit',
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const COMPLIANCE_PATTERNS = [
|
|
65
|
+
{ pattern: /(?:you\s+should\s+)?(?:buy|sell|invest\s+in)\s+(?:stocks?|crypto|bitcoin)/i, label: 'financial advice' },
|
|
66
|
+
{ pattern: /(?:you\s+(?:have|probably\s+have)|diagnos(?:e|is))\s+(?:\w+\s+){0,3}(?:disease|syndrome|disorder|cancer)/i, label: 'medical diagnosis' },
|
|
67
|
+
{ pattern: /(?:legal(?:ly)?|sue|lawsuit|court)\s+(?:you\s+should|advice)/i, label: 'legal advice' },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
// ── Rule Executors ──────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
function checkPII(text: string, action: string): { violations: GuardrailViolation[]; redactedText: string } {
|
|
73
|
+
const violations: GuardrailViolation[] = [];
|
|
74
|
+
let redacted = text;
|
|
75
|
+
for (const [type, pattern] of Object.entries(PII_PATTERNS)) {
|
|
76
|
+
const cloned = new RegExp(pattern.source, pattern.flags);
|
|
77
|
+
const matches = text.match(cloned);
|
|
78
|
+
if (matches) {
|
|
79
|
+
violations.push({ rule: 'pii-detector', action, detail: `Found ${type}: ${matches.length} match(es)` });
|
|
80
|
+
redacted = redacted.replace(cloned, '[REDACTED]');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { violations, redactedText: redacted };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function checkInjection(text: string): GuardrailViolation[] {
|
|
87
|
+
const violations: GuardrailViolation[] = [];
|
|
88
|
+
for (const pattern of INJECTION_PATTERNS) {
|
|
89
|
+
if (pattern.test(text)) {
|
|
90
|
+
violations.push({ rule: 'prompt-injection', action: 'block', detail: `Matched pattern: ${pattern.source}` });
|
|
91
|
+
break; // one is enough
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return violations;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function checkToxicity(text: string, extraKeywords?: string[]): GuardrailViolation[] {
|
|
98
|
+
const lower = text.toLowerCase();
|
|
99
|
+
const keywords = [...TOXICITY_KEYWORDS, ...(extraKeywords ?? [])];
|
|
100
|
+
for (const kw of keywords) {
|
|
101
|
+
if (lower.includes(kw.toLowerCase())) {
|
|
102
|
+
return [{ rule: 'toxicity', action: 'block', detail: `Matched keyword: "${kw}"` }];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function checkTopicRestriction(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
109
|
+
const denyTopics: string[] = config?.denyTopics ?? [];
|
|
110
|
+
const lower = text.toLowerCase();
|
|
111
|
+
for (const topic of denyTopics) {
|
|
112
|
+
if (lower.includes(topic.toLowerCase())) {
|
|
113
|
+
return [{ rule: 'topic-restrictor', action: 'block', detail: `Blocked topic: "${topic}"` }];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function checkLength(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
120
|
+
const maxChars = config?.maxChars ?? 10000;
|
|
121
|
+
if (text.length > maxChars) {
|
|
122
|
+
return [{ rule: 'length-limit', action: 'warn', detail: `Response length ${text.length} exceeds max ${maxChars}` }];
|
|
123
|
+
}
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function checkLanguage(text: string, config?: Record<string, any>): GuardrailViolation[] {
|
|
128
|
+
const allowed: string[] = config?.allowedLanguages ?? [];
|
|
129
|
+
if (allowed.length === 0) return [];
|
|
130
|
+
// Simple heuristic: check if text contains CJK characters
|
|
131
|
+
const hasCJK = /[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff]/.test(text);
|
|
132
|
+
const hasLatin = /[a-zA-Z]{3,}/.test(text);
|
|
133
|
+
if (allowed.includes('en') && !allowed.includes('zh') && hasCJK && !hasLatin) {
|
|
134
|
+
return [{ rule: 'language-filter', action: 'block', detail: 'Non-allowed language detected' }];
|
|
135
|
+
}
|
|
136
|
+
if (allowed.includes('zh') && !allowed.includes('en') && hasLatin && !hasCJK) {
|
|
137
|
+
return [{ rule: 'language-filter', action: 'block', detail: 'Non-allowed language detected' }];
|
|
138
|
+
}
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function checkCompliance(text: string): GuardrailViolation[] {
|
|
143
|
+
for (const { pattern, label } of COMPLIANCE_PATTERNS) {
|
|
144
|
+
if (pattern.test(text)) {
|
|
145
|
+
return [{ rule: 'compliance-filter', action: 'block', detail: `Potential ${label} detected` }];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ── Guardrail Manager ───────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
export class GuardrailManager {
|
|
154
|
+
private config: GuardrailConfig;
|
|
155
|
+
|
|
156
|
+
constructor(config: GuardrailConfig) {
|
|
157
|
+
this.config = config;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async checkInput(message: string): Promise<GuardrailResult> {
|
|
161
|
+
return this.runRules(message, this.config.input ?? []);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async checkOutput(response: string): Promise<GuardrailResult> {
|
|
165
|
+
return this.runRules(response, this.config.output ?? []);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private async runRules(text: string, rules: GuardrailRule[]): Promise<GuardrailResult> {
|
|
169
|
+
const allViolations: GuardrailViolation[] = [];
|
|
170
|
+
let blocked = false;
|
|
171
|
+
let warned = false;
|
|
172
|
+
let redacted = false;
|
|
173
|
+
let redactedText = text;
|
|
174
|
+
let blockMessage = '';
|
|
175
|
+
|
|
176
|
+
for (const rule of rules) {
|
|
177
|
+
let violations: GuardrailViolation[] = [];
|
|
178
|
+
|
|
179
|
+
switch (rule.name) {
|
|
180
|
+
case 'pii-detector': {
|
|
181
|
+
const result = checkPII(text, rule.action);
|
|
182
|
+
violations = result.violations;
|
|
183
|
+
if (violations.length > 0 && rule.action === 'redact') {
|
|
184
|
+
redacted = true;
|
|
185
|
+
redactedText = result.redactedText;
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'prompt-injection':
|
|
190
|
+
violations = checkInjection(text);
|
|
191
|
+
break;
|
|
192
|
+
case 'toxicity':
|
|
193
|
+
violations = checkToxicity(text, rule.config?.keywords);
|
|
194
|
+
break;
|
|
195
|
+
case 'topic-restrictor':
|
|
196
|
+
violations = checkTopicRestriction(text, rule.config);
|
|
197
|
+
break;
|
|
198
|
+
case 'length-limit':
|
|
199
|
+
violations = checkLength(text, rule.config);
|
|
200
|
+
break;
|
|
201
|
+
case 'language-filter':
|
|
202
|
+
violations = checkLanguage(text, rule.config);
|
|
203
|
+
break;
|
|
204
|
+
case 'compliance-filter':
|
|
205
|
+
violations = checkCompliance(text);
|
|
206
|
+
break;
|
|
207
|
+
default:
|
|
208
|
+
// Unknown rule — skip
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (violations.length > 0) {
|
|
213
|
+
// Override action from rule config
|
|
214
|
+
violations = violations.map(v => ({ ...v, action: rule.action }));
|
|
215
|
+
allViolations.push(...violations);
|
|
216
|
+
|
|
217
|
+
if (rule.action === 'block') {
|
|
218
|
+
blocked = true;
|
|
219
|
+
blockMessage = `Message blocked by ${rule.name}: ${violations[0].detail}`;
|
|
220
|
+
} else if (rule.action === 'warn') {
|
|
221
|
+
warned = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
passed: allViolations.length === 0,
|
|
228
|
+
blocked,
|
|
229
|
+
warned,
|
|
230
|
+
redacted,
|
|
231
|
+
message: blocked ? blockMessage : undefined,
|
|
232
|
+
redactedText: redacted ? redactedText : undefined,
|
|
233
|
+
violations: allViolations,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ── Factory from OAD config ─────────────────────────────────
|
|
239
|
+
|
|
240
|
+
export function createGuardrailsFromConfig(config: {
|
|
241
|
+
input?: Array<{ name: string; type: string; action: string; config?: any }>;
|
|
242
|
+
output?: Array<{ name: string; type: string; action: string; config?: any }>;
|
|
243
|
+
}): GuardrailManager {
|
|
244
|
+
return new GuardrailManager({
|
|
245
|
+
input: config.input as GuardrailRule[],
|
|
246
|
+
output: config.output as GuardrailRule[],
|
|
247
|
+
});
|
|
248
|
+
}
|
package/src/security/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { ApprovalManager } from './approval';
|
|
2
|
-
export type { ApprovalPolicy, ApprovalRequest } from './approval';
|
|
3
|
-
export { KeyManager } from './keys';
|
|
4
|
-
export { ExecApprovalManager } from './approvals';
|
|
5
|
-
export type { ExecApprovalPolicy, ExecApprovalRequest, ExecApprovalHistory, ApprovalRequestCallback } from './approvals';
|
|
6
|
-
export { ElevatedManager } from './elevated';
|
|
7
|
-
export type { ElevationMode, ElevationAuditEntry } from './elevated';
|
|
8
|
-
export { SecretsManager } from './secrets';
|
|
9
|
-
export type { SecretsStore } from './secrets';
|
|
1
|
+
export { ApprovalManager } from './approval';
|
|
2
|
+
export type { ApprovalPolicy, ApprovalRequest } from './approval';
|
|
3
|
+
export { KeyManager } from './keys';
|
|
4
|
+
export { ExecApprovalManager } from './approvals';
|
|
5
|
+
export type { ExecApprovalPolicy, ExecApprovalRequest, ExecApprovalHistory, ApprovalRequestCallback } from './approvals';
|
|
6
|
+
export { ElevatedManager } from './elevated';
|
|
7
|
+
export type { ElevationMode, ElevationAuditEntry } from './elevated';
|
|
8
|
+
export { SecretsManager } from './secrets';
|
|
9
|
+
export type { SecretsStore } from './secrets';
|