@aporthq/aport-agent-guardrails 1.0.21 → 1.0.23
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/README.md +8 -3
- package/bin/openclaw +82 -31
- package/docs/PROVIDER.md +6 -6
- package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +42 -408
- package/docs/RELEASE.md +3 -2
- package/docs/TOOL_POLICY_MAPPING.md +2 -2
- package/docs/frameworks/openclaw.md +137 -38
- package/extensions/openclaw-aport/CHANGELOG.md +14 -1
- package/extensions/openclaw-aport/MIGRATION.md +22 -375
- package/extensions/openclaw-aport/README.md +88 -350
- package/extensions/openclaw-aport/api-client.js +30 -0
- package/extensions/openclaw-aport/audit.js +32 -0
- package/extensions/openclaw-aport/decision.js +21 -0
- package/extensions/openclaw-aport/index.js +169 -592
- package/extensions/openclaw-aport/local-evaluator.js +303 -0
- package/extensions/openclaw-aport/openclaw.plugin.json +5 -5
- package/extensions/openclaw-aport/package-lock.json +2 -2
- package/extensions/openclaw-aport/package.json +27 -6
- package/extensions/openclaw-aport/tool-mapping.js +276 -0
- package/package.json +1 -1
- package/extensions/openclaw-aport/index.ts +0 -547
- package/extensions/openclaw-aport/test.js +0 -356
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
const MESSAGE_SEND_ACTIONS = new Set([
|
|
2
|
+
"send",
|
|
3
|
+
"broadcast",
|
|
4
|
+
"reply",
|
|
5
|
+
"thread-reply",
|
|
6
|
+
"sendwitheffect",
|
|
7
|
+
"sendattachment",
|
|
8
|
+
"upload-file",
|
|
9
|
+
"react",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
function firstNonEmpty(...values) {
|
|
13
|
+
for (const value of values) {
|
|
14
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
15
|
+
}
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function readAction(params) {
|
|
20
|
+
const src = params && typeof params === "object" ? params : {};
|
|
21
|
+
return firstNonEmpty(
|
|
22
|
+
src.action,
|
|
23
|
+
src.action_name,
|
|
24
|
+
src.actionName,
|
|
25
|
+
src.arguments && typeof src.arguments === "object" ? src.arguments.action : "",
|
|
26
|
+
src.input && typeof src.input === "object" ? src.input.action : "",
|
|
27
|
+
).toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function parseMcpToolName(toolName) {
|
|
31
|
+
const raw = String(toolName ?? "").trim();
|
|
32
|
+
if (!raw) return null;
|
|
33
|
+
|
|
34
|
+
if (raw.startsWith("mcp__")) {
|
|
35
|
+
const parts = raw.split("__");
|
|
36
|
+
if (parts.length >= 3 && parts[1] && parts.slice(2).join("__")) {
|
|
37
|
+
return {
|
|
38
|
+
serverName: parts[1],
|
|
39
|
+
toolName: parts.slice(2).join("__"),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const separatorIndex = raw.indexOf("__");
|
|
45
|
+
if (separatorIndex <= 0 || separatorIndex >= raw.length - 2) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
serverName: raw.slice(0, separatorIndex),
|
|
51
|
+
toolName: raw.slice(separatorIndex + 2),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function mapToolToPolicy(toolName, params) {
|
|
56
|
+
const rawTool = String(toolName ?? "").trim();
|
|
57
|
+
const tool = rawTool.toLowerCase();
|
|
58
|
+
|
|
59
|
+
if (tool.match(/git\.(create_pr|merge|push|commit)/)) return "code.repository.merge.v1";
|
|
60
|
+
if (tool.startsWith("git.")) return "code.repository.merge.v1";
|
|
61
|
+
|
|
62
|
+
if (tool === "exec") return "system.command.execute.v1";
|
|
63
|
+
if (tool.match(/exec\.(run|shell)/)) return "system.command.execute.v1";
|
|
64
|
+
if (tool.startsWith("exec.")) return "system.command.execute.v1";
|
|
65
|
+
if (tool.startsWith("system.command.")) return "system.command.execute.v1";
|
|
66
|
+
if (tool === "bash" || tool === "shell" || tool === "command") return "system.command.execute.v1";
|
|
67
|
+
|
|
68
|
+
if (tool === "message") {
|
|
69
|
+
return MESSAGE_SEND_ACTIONS.has(readAction(params)) ? "messaging.message.send.v1" : null;
|
|
70
|
+
}
|
|
71
|
+
if (
|
|
72
|
+
tool === "message.send" ||
|
|
73
|
+
tool === "message.reply" ||
|
|
74
|
+
tool === "message.broadcast" ||
|
|
75
|
+
tool === "message.react" ||
|
|
76
|
+
tool === "messaging.message.send"
|
|
77
|
+
) {
|
|
78
|
+
return "messaging.message.send.v1";
|
|
79
|
+
}
|
|
80
|
+
if (tool.match(/(^|[._-])(whatsapp|telegram|slack|email)([._-](send|reply|broadcast|message|react))?$/)) {
|
|
81
|
+
return "messaging.message.send.v1";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (tool === "read") return "data.file.read.v1";
|
|
85
|
+
if (tool.startsWith("file.read")) return "data.file.read.v1";
|
|
86
|
+
if (tool.startsWith("data.file.read")) return "data.file.read.v1";
|
|
87
|
+
if (tool === "write" || tool === "edit") return "data.file.write.v1";
|
|
88
|
+
if (tool === "multiedit" || tool === "notebookedit") return "data.file.write.v1";
|
|
89
|
+
if (tool === "glob" || tool === "ls" || tool === "grep" || tool === "toolsearch") {
|
|
90
|
+
return "data.file.read.v1";
|
|
91
|
+
}
|
|
92
|
+
if (tool === "todoread") return "data.file.read.v1";
|
|
93
|
+
if (tool === "todowrite") return "data.file.write.v1";
|
|
94
|
+
if (tool === "taskget" || tool === "tasklist" || tool === "taskoutput") return "data.file.read.v1";
|
|
95
|
+
if (tool === "askuserquestion" || tool === "enterplanmode" || tool === "exitplanmode") return null;
|
|
96
|
+
if (tool === "cronlist") return "data.file.read.v1";
|
|
97
|
+
if (tool.startsWith("file.write")) return "data.file.write.v1";
|
|
98
|
+
if (tool.startsWith("file.edit")) return "data.file.write.v1";
|
|
99
|
+
if (tool.startsWith("data.file.write")) return "data.file.write.v1";
|
|
100
|
+
|
|
101
|
+
if (tool === "web_fetch" || tool === "webfetch") return "web.fetch.v1";
|
|
102
|
+
if (tool === "web_search" || tool === "websearch") return "web.fetch.v1";
|
|
103
|
+
if (tool.startsWith("web.fetch")) return "web.fetch.v1";
|
|
104
|
+
if (tool.startsWith("web.search")) return "web.fetch.v1";
|
|
105
|
+
if (tool === "browser") return "web.browser.v1";
|
|
106
|
+
if (tool.startsWith("web.browser")) return "web.browser.v1";
|
|
107
|
+
if (tool.startsWith("browser.")) return "web.browser.v1";
|
|
108
|
+
|
|
109
|
+
if (tool.startsWith("mcp.")) return "mcp.tool.execute.v1";
|
|
110
|
+
if (parseMcpToolName(rawTool)) return "mcp.tool.execute.v1";
|
|
111
|
+
|
|
112
|
+
if (tool === "gateway" || tool.startsWith("gateway.")) return "system.command.execute.v1";
|
|
113
|
+
if (tool === "process" || tool.startsWith("process.")) return "system.command.execute.v1";
|
|
114
|
+
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function normalizeExecContext(params, event) {
|
|
119
|
+
const src = event && typeof event === "object" ? { ...event, ...params } : params || {};
|
|
120
|
+
if (!src || typeof src !== "object") return { command: "" };
|
|
121
|
+
|
|
122
|
+
const raw =
|
|
123
|
+
src.command ??
|
|
124
|
+
src.cmd ??
|
|
125
|
+
(src.arguments && typeof src.arguments === "object" ? src.arguments.command : null) ??
|
|
126
|
+
(src.input && typeof src.input === "object" ? src.input.command : null) ??
|
|
127
|
+
(typeof src.input === "string" && src.input.trim().length > 0 ? src.input : null) ??
|
|
128
|
+
(src.args && typeof src.args === "object" ? src.args.command : null) ??
|
|
129
|
+
(src.invocation && typeof src.invocation === "object" ? src.invocation.command : null) ??
|
|
130
|
+
(src.payload && typeof src.payload === "object" ? src.payload.command : null) ??
|
|
131
|
+
(Array.isArray(src.args) && src.args.length > 0 ? src.args.join(" ") : src.args?.[0]);
|
|
132
|
+
|
|
133
|
+
const full = typeof raw === "string" ? raw : raw != null ? String(raw) : "";
|
|
134
|
+
const out = { ...(params || {}), command: full, full_command: full };
|
|
135
|
+
if (params && params.workdir !== undefined && out.cwd === undefined) out.cwd = params.workdir;
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function normalizeFileContext(params) {
|
|
140
|
+
const src = params && typeof params === "object" ? params : {};
|
|
141
|
+
const filePath =
|
|
142
|
+
src.file_path ??
|
|
143
|
+
src.path ??
|
|
144
|
+
src.filePath ??
|
|
145
|
+
(src.arguments && typeof src.arguments === "object" ? src.arguments.file_path ?? src.arguments.path : null) ??
|
|
146
|
+
(src.input && typeof src.input === "object" ? src.input.file_path ?? src.input.path : null) ??
|
|
147
|
+
(src.args && typeof src.args === "object" ? src.args.file_path ?? src.args.path : null);
|
|
148
|
+
|
|
149
|
+
if (filePath == null || String(filePath).trim() === "") {
|
|
150
|
+
return { ...src };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
...src,
|
|
155
|
+
file_path: String(filePath),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function normalizeMessageContext(params) {
|
|
160
|
+
const src = params && typeof params === "object" ? params : {};
|
|
161
|
+
const action = readAction(src);
|
|
162
|
+
const firstTarget = Array.isArray(src.targets)
|
|
163
|
+
? src.targets.find((value) => typeof value === "string" && value.trim())
|
|
164
|
+
: "";
|
|
165
|
+
const channelId = firstNonEmpty(
|
|
166
|
+
src.channel_id,
|
|
167
|
+
src.channelId,
|
|
168
|
+
src.target,
|
|
169
|
+
firstTarget,
|
|
170
|
+
src.channel,
|
|
171
|
+
src.to,
|
|
172
|
+
src.accountId,
|
|
173
|
+
);
|
|
174
|
+
const isAttachmentAction =
|
|
175
|
+
action === "sendattachment" ||
|
|
176
|
+
action === "upload-file" ||
|
|
177
|
+
Boolean(src.media || src.buffer || src.path || src.filePath || src.filename);
|
|
178
|
+
const messageType = action === "react" ? "reaction" : isAttachmentAction ? "file" : "text";
|
|
179
|
+
const message = firstNonEmpty(
|
|
180
|
+
src.message,
|
|
181
|
+
src.text,
|
|
182
|
+
src.content,
|
|
183
|
+
src.caption,
|
|
184
|
+
src.quoteText,
|
|
185
|
+
src.emoji,
|
|
186
|
+
isAttachmentAction ? src.filename : "",
|
|
187
|
+
);
|
|
188
|
+
const threadId = firstNonEmpty(src.thread_id, src.threadId);
|
|
189
|
+
const replyTo = firstNonEmpty(src.reply_to, src.replyTo, src.messageId, src.message_id);
|
|
190
|
+
const out = {
|
|
191
|
+
...src,
|
|
192
|
+
message_type: src.message_type ?? messageType,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (channelId) out.channel_id = channelId;
|
|
196
|
+
if (message) out.message = message;
|
|
197
|
+
else if (messageType === "reaction") out.message = "reaction";
|
|
198
|
+
else if (messageType === "file") out.message = "[attachment]";
|
|
199
|
+
|
|
200
|
+
if (threadId) out.thread_id = threadId;
|
|
201
|
+
if (replyTo) out.reply_to = replyTo;
|
|
202
|
+
|
|
203
|
+
if (!Array.isArray(out.attachments) && isAttachmentAction) {
|
|
204
|
+
out.attachments = [
|
|
205
|
+
{
|
|
206
|
+
...(typeof src.media === "string" && src.media ? { url: src.media } : {}),
|
|
207
|
+
...(typeof src.filename === "string" && src.filename ? { filename: src.filename } : {}),
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buildMcpParameters(src) {
|
|
216
|
+
if (src.parameters && typeof src.parameters === "object") return src.parameters;
|
|
217
|
+
if (src.arguments && typeof src.arguments === "object") return src.arguments;
|
|
218
|
+
if (src.input && typeof src.input === "object") return src.input;
|
|
219
|
+
if (src.payload && typeof src.payload === "object") return src.payload;
|
|
220
|
+
|
|
221
|
+
const {
|
|
222
|
+
server,
|
|
223
|
+
server_url,
|
|
224
|
+
serverUrl,
|
|
225
|
+
server_name,
|
|
226
|
+
serverName,
|
|
227
|
+
tool,
|
|
228
|
+
tool_name,
|
|
229
|
+
toolName,
|
|
230
|
+
parameters,
|
|
231
|
+
...rest
|
|
232
|
+
} = src;
|
|
233
|
+
return rest;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function normalizeMcpContext(toolName, params) {
|
|
237
|
+
const src = params && typeof params === "object" ? params : {};
|
|
238
|
+
const parsed = parseMcpToolName(toolName);
|
|
239
|
+
const serverName = firstNonEmpty(
|
|
240
|
+
src.server,
|
|
241
|
+
src.server_url,
|
|
242
|
+
src.serverUrl,
|
|
243
|
+
src.server_name,
|
|
244
|
+
src.serverName,
|
|
245
|
+
src.mcp_server,
|
|
246
|
+
parsed?.serverName,
|
|
247
|
+
);
|
|
248
|
+
const normalizedServer =
|
|
249
|
+
serverName && serverName.includes("://") ? serverName : serverName ? `mcp://${serverName}` : "";
|
|
250
|
+
const tool = firstNonEmpty(src.tool, src.tool_name, src.toolName, src.mcp_tool, parsed?.toolName);
|
|
251
|
+
const out = {
|
|
252
|
+
...src,
|
|
253
|
+
parameters: buildMcpParameters(src),
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
if (normalizedServer) out.server = normalizedServer;
|
|
257
|
+
if (tool) out.tool = tool;
|
|
258
|
+
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function normalizePolicyContext(policyName, toolName, params, event) {
|
|
263
|
+
if (policyName === "system.command.execute.v1") {
|
|
264
|
+
return normalizeExecContext(params, event);
|
|
265
|
+
}
|
|
266
|
+
if (policyName === "data.file.read.v1" || policyName === "data.file.write.v1") {
|
|
267
|
+
return normalizeFileContext(params);
|
|
268
|
+
}
|
|
269
|
+
if (policyName === "messaging.message.send.v1") {
|
|
270
|
+
return normalizeMessageContext(params);
|
|
271
|
+
}
|
|
272
|
+
if (policyName === "mcp.tool.execute.v1") {
|
|
273
|
+
return normalizeMcpContext(toolName, params);
|
|
274
|
+
}
|
|
275
|
+
return params || {};
|
|
276
|
+
}
|