@clawtrail/context-graph-openclaw 0.7.5 → 0.8.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/README.md +64 -56
- package/dist/OpenClawAdapter.d.ts +6 -6
- package/dist/OpenClawAdapter.d.ts.map +1 -1
- package/dist/OpenClawAdapter.js +46 -36
- package/dist/OpenClawAdapter.js.map +1 -1
- package/dist/detectors/BuildDetector.js +11 -11
- package/dist/detectors/HttpDetector.d.ts.map +1 -1
- package/dist/detectors/HttpDetector.js +20 -17
- package/dist/detectors/HttpDetector.js.map +1 -1
- package/dist/detectors/TestDetector.js +9 -9
- package/dist/hooks/lifecycle.d.ts +1 -1
- package/dist/hooks/lifecycle.js +4 -4
- package/dist/hooks/llmOutput.d.ts +2 -2
- package/dist/hooks/llmOutput.js +5 -5
- package/dist/hooks/toolCall.d.ts +3 -3
- package/dist/hooks/toolCall.d.ts.map +1 -1
- package/dist/hooks/toolCall.js +4 -4
- package/dist/hooks/toolCall.js.map +1 -1
- package/dist/index.d.ts +29 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/mappers/MapperRegistry.d.ts +4 -0
- package/dist/mappers/MapperRegistry.d.ts.map +1 -1
- package/dist/mappers/MapperRegistry.js +8 -0
- package/dist/mappers/MapperRegistry.js.map +1 -1
- package/dist/mappers/browser.d.ts +11 -0
- package/dist/mappers/browser.d.ts.map +1 -0
- package/dist/mappers/browser.js +66 -0
- package/dist/mappers/browser.js.map +1 -0
- package/dist/mappers/document.d.ts +7 -0
- package/dist/mappers/document.d.ts.map +1 -0
- package/dist/mappers/document.js +49 -0
- package/dist/mappers/document.js.map +1 -0
- package/dist/mappers/fallback.d.ts +1 -1
- package/dist/mappers/fallback.js +3 -3
- package/dist/mappers/fs.d.ts +1 -1
- package/dist/mappers/fs.d.ts.map +1 -1
- package/dist/mappers/fs.js +11 -11
- package/dist/mappers/fs.js.map +1 -1
- package/dist/mappers/git.d.ts +1 -1
- package/dist/mappers/git.d.ts.map +1 -1
- package/dist/mappers/git.js +21 -14
- package/dist/mappers/git.js.map +1 -1
- package/dist/mappers/message.d.ts +11 -0
- package/dist/mappers/message.d.ts.map +1 -0
- package/dist/mappers/message.js +72 -0
- package/dist/mappers/message.js.map +1 -0
- package/dist/mappers/session.d.ts +12 -0
- package/dist/mappers/session.d.ts.map +1 -0
- package/dist/mappers/session.js +71 -0
- package/dist/mappers/session.js.map +1 -0
- package/dist/mappers/shell.d.ts +4 -4
- package/dist/mappers/shell.d.ts.map +1 -1
- package/dist/mappers/shell.js +17 -15
- package/dist/mappers/shell.js.map +1 -1
- package/dist/mappers/web.d.ts +11 -0
- package/dist/mappers/web.d.ts.map +1 -0
- package/dist/mappers/web.js +89 -0
- package/dist/mappers/web.js.map +1 -0
- package/dist/register.d.ts.map +1 -1
- package/dist/register.js +195 -17
- package/dist/register.js.map +1 -1
- package/dist/rules/openclaw-rules.d.ts +7 -1
- package/dist/rules/openclaw-rules.d.ts.map +1 -1
- package/dist/rules/openclaw-rules.js +321 -120
- package/dist/rules/openclaw-rules.js.map +1 -1
- package/dist/tools/status.d.ts +1 -1
- package/dist/tools/status.js +3 -3
- package/dist/tools/summarize.d.ts +1 -1
- package/dist/tools/summarize.d.ts.map +1 -1
- package/dist/tools/summarize.js +5 -5
- package/dist/tools/summarize.js.map +1 -1
- package/dist/util/hash.d.ts +1 -1
- package/dist/util/hash.d.ts.map +1 -1
- package/dist/util/hash.js +52 -43
- package/dist/util/hash.js.map +1 -1
- package/openclaw.plugin.json +5 -1
- package/package.json +6 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { compositeConfidence, wilsonScoreLower } from
|
|
2
|
-
import { extensionToLanguage } from
|
|
1
|
+
import { compositeConfidence, wilsonScoreLower, } from "@clawtrail/context-graph";
|
|
2
|
+
import { extensionToLanguage } from "../util/hash.js";
|
|
3
3
|
// ── Helpers ─────────────────────────────────────────────────────────
|
|
4
4
|
/** Get age in ms of the latest event in a list, relative to now */
|
|
5
5
|
function latestAge(events) {
|
|
@@ -14,13 +14,13 @@ function countByStatus(events, status) {
|
|
|
14
14
|
}
|
|
15
15
|
// ── CLI Agent Rules (kept for coding agents — dynamic confidence) ──
|
|
16
16
|
export const CanFixBuild = {
|
|
17
|
-
id:
|
|
18
|
-
name:
|
|
19
|
-
description:
|
|
17
|
+
id: "cg:CanFixBuild",
|
|
18
|
+
name: "Can Fix Build",
|
|
19
|
+
description: "Agent recovered a failing build within the same session",
|
|
20
20
|
evaluate(ctx) {
|
|
21
|
-
const buildRuns = ctx.events.filter((e) => e.type ===
|
|
22
|
-
const failed = buildRuns.filter((e) => e.status ===
|
|
23
|
-
const succeeded = buildRuns.filter((e) => e.status ===
|
|
21
|
+
const buildRuns = ctx.events.filter((e) => e.type === "BUILD_RUN");
|
|
22
|
+
const failed = buildRuns.filter((e) => e.status === "FAILED" || e.data.exit_code !== 0);
|
|
23
|
+
const succeeded = buildRuns.filter((e) => e.status === "SUCCEEDED" && e.data.exit_code === 0);
|
|
24
24
|
const recoveries = [];
|
|
25
25
|
for (const fail of failed) {
|
|
26
26
|
const recovery = succeeded.find((s) => s.ts > fail.ts);
|
|
@@ -30,23 +30,24 @@ export const CanFixBuild = {
|
|
|
30
30
|
if (recoveries.length === 0)
|
|
31
31
|
return [];
|
|
32
32
|
const { confidence } = compositeConfidence(recoveries.length, failed.length - recoveries.length, latestAge(recoveries));
|
|
33
|
-
return [
|
|
34
|
-
|
|
33
|
+
return [
|
|
34
|
+
{
|
|
35
|
+
claimType: "cg:CanFixBuild",
|
|
35
36
|
confidence,
|
|
36
37
|
scope: (failed[0]?.data.tool || recoveries[0]?.data.tool),
|
|
37
38
|
evidenceHashes: [...failed, ...recoveries].map((e) => e.event_hash),
|
|
38
|
-
}
|
|
39
|
+
},
|
|
40
|
+
];
|
|
39
41
|
},
|
|
40
42
|
};
|
|
41
43
|
export const CanFixTests = {
|
|
42
|
-
id:
|
|
43
|
-
name:
|
|
44
|
-
description:
|
|
44
|
+
id: "cg:CanFixTests",
|
|
45
|
+
name: "Can Fix Tests",
|
|
46
|
+
description: "Agent recovered failing tests within the same session",
|
|
45
47
|
evaluate(ctx) {
|
|
46
|
-
const testRuns = ctx.events.filter((e) => e.type ===
|
|
47
|
-
const failed = testRuns.filter((e) => e.status ===
|
|
48
|
-
|
|
49
|
-
const succeeded = testRuns.filter((e) => e.status === 'SUCCEEDED' && e.data.failed === 0);
|
|
48
|
+
const testRuns = ctx.events.filter((e) => e.type === "TEST_RUN");
|
|
49
|
+
const failed = testRuns.filter((e) => e.status === "FAILED" || e.data.failed > 0);
|
|
50
|
+
const succeeded = testRuns.filter((e) => e.status === "SUCCEEDED" && e.data.failed === 0);
|
|
50
51
|
const recoveries = [];
|
|
51
52
|
for (const fail of failed) {
|
|
52
53
|
const recovery = succeeded.find((s) => s.ts > fail.ts);
|
|
@@ -56,30 +57,34 @@ export const CanFixTests = {
|
|
|
56
57
|
if (recoveries.length === 0)
|
|
57
58
|
return [];
|
|
58
59
|
const { confidence } = compositeConfidence(recoveries.length, failed.length - recoveries.length, latestAge(recoveries));
|
|
59
|
-
return [
|
|
60
|
-
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
claimType: "cg:CanFixTests",
|
|
61
63
|
confidence,
|
|
62
64
|
scope: (failed[0]?.data.framework || recoveries[0]?.data.framework),
|
|
63
65
|
evidenceHashes: [...failed, ...recoveries].map((e) => e.event_hash),
|
|
64
|
-
}
|
|
66
|
+
},
|
|
67
|
+
];
|
|
65
68
|
},
|
|
66
69
|
};
|
|
67
70
|
export const CanRunTests = {
|
|
68
|
-
id:
|
|
69
|
-
name:
|
|
70
|
-
description:
|
|
71
|
+
id: "cg:CanRunTests",
|
|
72
|
+
name: "Can Run Tests",
|
|
73
|
+
description: "Agent successfully ran tests multiple times",
|
|
71
74
|
evaluate(ctx) {
|
|
72
|
-
const successful = ctx.events.filter((e) => e.type ===
|
|
75
|
+
const successful = ctx.events.filter((e) => e.type === "TEST_RUN" && e.status === "SUCCEEDED");
|
|
73
76
|
if (successful.length < 2)
|
|
74
77
|
return [];
|
|
75
|
-
const allTestRuns = ctx.events.filter((e) => e.type ===
|
|
76
|
-
const frameworks = [
|
|
78
|
+
const allTestRuns = ctx.events.filter((e) => e.type === "TEST_RUN");
|
|
79
|
+
const frameworks = [
|
|
80
|
+
...new Set(successful.map((e) => e.data.framework)),
|
|
81
|
+
];
|
|
77
82
|
return frameworks.map((fw) => {
|
|
78
83
|
const fwEvents = allTestRuns.filter((e) => e.data.framework === fw);
|
|
79
|
-
const fwSucceeded = fwEvents.filter((e) => e.status ===
|
|
84
|
+
const fwSucceeded = fwEvents.filter((e) => e.status === "SUCCEEDED").length;
|
|
80
85
|
const { confidence } = compositeConfidence(fwSucceeded, fwEvents.length - fwSucceeded, latestAge(fwEvents));
|
|
81
86
|
return {
|
|
82
|
-
claimType:
|
|
87
|
+
claimType: "cg:CanRunTests",
|
|
83
88
|
confidence,
|
|
84
89
|
scope: fw,
|
|
85
90
|
evidenceHashes: fwEvents.map((e) => e.event_hash),
|
|
@@ -88,34 +93,39 @@ export const CanRunTests = {
|
|
|
88
93
|
},
|
|
89
94
|
};
|
|
90
95
|
export const CanRecoverFromError = {
|
|
91
|
-
id:
|
|
92
|
-
name:
|
|
93
|
-
description:
|
|
96
|
+
id: "cg:CanRecoverFromError",
|
|
97
|
+
name: "Can Recover From Error",
|
|
98
|
+
description: "Agent recovered from an error by succeeding on the same artifact",
|
|
94
99
|
evaluate(ctx) {
|
|
95
|
-
const errors = ctx.events.filter((e) => e.type ===
|
|
100
|
+
const errors = ctx.events.filter((e) => e.type === "ERROR");
|
|
96
101
|
const recoveries = [];
|
|
97
102
|
for (const err of errors) {
|
|
98
|
-
const laterSuccess = ctx.events.find((e) => e.ts > err.ts && e.status ===
|
|
103
|
+
const laterSuccess = ctx.events.find((e) => e.ts > err.ts && e.status === "SUCCEEDED");
|
|
99
104
|
if (laterSuccess)
|
|
100
105
|
recoveries.push({ error: err, success: laterSuccess });
|
|
101
106
|
}
|
|
102
107
|
if (recoveries.length === 0)
|
|
103
108
|
return [];
|
|
104
109
|
const { confidence } = compositeConfidence(recoveries.length, errors.length - recoveries.length, latestAge(recoveries.map((r) => r.success)));
|
|
105
|
-
return [
|
|
106
|
-
|
|
110
|
+
return [
|
|
111
|
+
{
|
|
112
|
+
claimType: "cg:CanRecoverFromError",
|
|
107
113
|
confidence,
|
|
108
|
-
evidenceHashes: recoveries.flatMap((r) => [
|
|
109
|
-
|
|
114
|
+
evidenceHashes: recoveries.flatMap((r) => [
|
|
115
|
+
r.error.event_hash,
|
|
116
|
+
r.success.event_hash,
|
|
117
|
+
]),
|
|
118
|
+
},
|
|
119
|
+
];
|
|
110
120
|
},
|
|
111
121
|
};
|
|
112
122
|
export const CanWriteCode = {
|
|
113
|
-
id:
|
|
114
|
-
name:
|
|
115
|
-
description:
|
|
123
|
+
id: "cg:CanWrite",
|
|
124
|
+
name: "Can Write Code",
|
|
125
|
+
description: "Agent wrote files in specific languages",
|
|
116
126
|
evaluate(ctx) {
|
|
117
|
-
const writes = ctx.events.filter((e) => e.type ===
|
|
118
|
-
const allWrites = ctx.events.filter((e) => e.type ===
|
|
127
|
+
const writes = ctx.events.filter((e) => e.type === "FILE_WRITE" && e.status === "SUCCEEDED");
|
|
128
|
+
const allWrites = ctx.events.filter((e) => e.type === "FILE_WRITE");
|
|
119
129
|
const extCounts = new Map();
|
|
120
130
|
for (const w of writes) {
|
|
121
131
|
const ext = w.data.path_extension;
|
|
@@ -129,7 +139,7 @@ export const CanWriteCode = {
|
|
|
129
139
|
const totalForExt = allWrites.filter((e) => e.data.path_extension === ext).length;
|
|
130
140
|
const { confidence } = compositeConfidence(hashes.length, totalForExt - hashes.length, latestAge(writes.filter((e) => e.data.path_extension === ext)));
|
|
131
141
|
return {
|
|
132
|
-
claimType:
|
|
142
|
+
claimType: "cg:CanWrite",
|
|
133
143
|
confidence,
|
|
134
144
|
scope: extensionToLanguage(ext),
|
|
135
145
|
evidenceHashes: hashes,
|
|
@@ -138,16 +148,16 @@ export const CanWriteCode = {
|
|
|
138
148
|
},
|
|
139
149
|
};
|
|
140
150
|
export const CanUseFramework = {
|
|
141
|
-
id:
|
|
142
|
-
name:
|
|
143
|
-
description:
|
|
151
|
+
id: "cg:CanUseFramework",
|
|
152
|
+
name: "Can Use Framework",
|
|
153
|
+
description: "Agent used specific test/build frameworks",
|
|
144
154
|
evaluate(ctx) {
|
|
145
155
|
const frameworks = new Map();
|
|
146
156
|
for (const e of ctx.events) {
|
|
147
157
|
let fw;
|
|
148
|
-
if (e.type ===
|
|
158
|
+
if (e.type === "TEST_RUN")
|
|
149
159
|
fw = e.data.framework;
|
|
150
|
-
if (e.type ===
|
|
160
|
+
if (e.type === "BUILD_RUN")
|
|
151
161
|
fw = e.data.tool;
|
|
152
162
|
if (fw) {
|
|
153
163
|
if (!frameworks.has(fw))
|
|
@@ -156,10 +166,10 @@ export const CanUseFramework = {
|
|
|
156
166
|
}
|
|
157
167
|
}
|
|
158
168
|
return [...frameworks.entries()].map(([fw, events]) => {
|
|
159
|
-
const succeeded = countByStatus(events,
|
|
169
|
+
const succeeded = countByStatus(events, "SUCCEEDED");
|
|
160
170
|
const { confidence } = compositeConfidence(succeeded, events.length - succeeded, latestAge(events));
|
|
161
171
|
return {
|
|
162
|
-
claimType:
|
|
172
|
+
claimType: "cg:CanUseFramework",
|
|
163
173
|
confidence,
|
|
164
174
|
scope: fw,
|
|
165
175
|
evidenceHashes: events.map((e) => e.event_hash),
|
|
@@ -168,16 +178,16 @@ export const CanUseFramework = {
|
|
|
168
178
|
},
|
|
169
179
|
};
|
|
170
180
|
export const CanUseTool = {
|
|
171
|
-
id:
|
|
172
|
-
name:
|
|
173
|
-
description:
|
|
181
|
+
id: "cg:CanUseTool",
|
|
182
|
+
name: "Can Use Tool",
|
|
183
|
+
description: "Agent used specific shell tools",
|
|
174
184
|
evaluate(ctx) {
|
|
175
185
|
const tools = new Map();
|
|
176
186
|
for (const e of ctx.events) {
|
|
177
|
-
if (e.type ===
|
|
187
|
+
if (e.type === "SHELL_COMMAND" || e.type === "TOOL_CALL") {
|
|
178
188
|
const toolName = (e.data.cmd_display || e.data.tool);
|
|
179
189
|
if (toolName) {
|
|
180
|
-
const baseTool = toolName.split(
|
|
190
|
+
const baseTool = toolName.split(" ")[0];
|
|
181
191
|
if (!tools.has(baseTool))
|
|
182
192
|
tools.set(baseTool, []);
|
|
183
193
|
tools.get(baseTool).push(e);
|
|
@@ -185,10 +195,10 @@ export const CanUseTool = {
|
|
|
185
195
|
}
|
|
186
196
|
}
|
|
187
197
|
return [...tools.entries()].map(([tool, events]) => {
|
|
188
|
-
const succeeded = countByStatus(events,
|
|
198
|
+
const succeeded = countByStatus(events, "SUCCEEDED");
|
|
189
199
|
const { confidence } = compositeConfidence(succeeded, events.length - succeeded, latestAge(events));
|
|
190
200
|
return {
|
|
191
|
-
claimType:
|
|
201
|
+
claimType: "cg:CanUseTool",
|
|
192
202
|
confidence,
|
|
193
203
|
scope: tool,
|
|
194
204
|
evidenceHashes: events.map((e) => e.event_hash),
|
|
@@ -197,20 +207,22 @@ export const CanUseTool = {
|
|
|
197
207
|
},
|
|
198
208
|
};
|
|
199
209
|
export const CanCallApis = {
|
|
200
|
-
id:
|
|
201
|
-
name:
|
|
202
|
-
description:
|
|
210
|
+
id: "cg:CanCallApis",
|
|
211
|
+
name: "Can Call APIs",
|
|
212
|
+
description: "Agent successfully called HTTP APIs",
|
|
203
213
|
evaluate(ctx) {
|
|
204
|
-
const httpCalls = ctx.events.filter((e) => e.type ===
|
|
214
|
+
const httpCalls = ctx.events.filter((e) => e.type === "HTTP_REQUEST");
|
|
205
215
|
if (httpCalls.length < 2)
|
|
206
216
|
return [];
|
|
207
|
-
const hosts = [
|
|
217
|
+
const hosts = [
|
|
218
|
+
...new Set(httpCalls.map((e) => e.data.host_hash)),
|
|
219
|
+
];
|
|
208
220
|
return hosts.map((h) => {
|
|
209
221
|
const hostEvents = httpCalls.filter((e) => e.data.host_hash === h);
|
|
210
|
-
const succeeded = countByStatus(hostEvents,
|
|
222
|
+
const succeeded = countByStatus(hostEvents, "SUCCEEDED");
|
|
211
223
|
const { confidence } = compositeConfidence(succeeded, hostEvents.length - succeeded, latestAge(hostEvents));
|
|
212
224
|
return {
|
|
213
|
-
claimType:
|
|
225
|
+
claimType: "cg:CanCallApis",
|
|
214
226
|
confidence,
|
|
215
227
|
scope: h,
|
|
216
228
|
evidenceHashes: hostEvents.map((e) => e.event_hash),
|
|
@@ -219,21 +231,21 @@ export const CanCallApis = {
|
|
|
219
231
|
},
|
|
220
232
|
};
|
|
221
233
|
export const CanHandleHttpErrors = {
|
|
222
|
-
id:
|
|
223
|
-
name:
|
|
224
|
-
description:
|
|
234
|
+
id: "cg:CanHandleHttpErrors",
|
|
235
|
+
name: "Can Handle HTTP Errors",
|
|
236
|
+
description: "Agent retried or recovered from HTTP errors",
|
|
225
237
|
evaluate(ctx) {
|
|
226
|
-
const httpCalls = ctx.events.filter((e) => e.type ===
|
|
238
|
+
const httpCalls = ctx.events.filter((e) => e.type === "HTTP_REQUEST");
|
|
227
239
|
const failed = httpCalls.filter((e) => {
|
|
228
240
|
const sc = e.data.status_code;
|
|
229
|
-
return e.status ===
|
|
241
|
+
return e.status === "FAILED" || (sc !== undefined && sc >= 400);
|
|
230
242
|
});
|
|
231
243
|
let recoveryCount = 0;
|
|
232
244
|
const evidenceHashes = [];
|
|
233
245
|
for (const fail of failed) {
|
|
234
246
|
const recovery = httpCalls.find((s) => s.ts > fail.ts &&
|
|
235
247
|
s.data.host_hash === fail.data.host_hash &&
|
|
236
|
-
s.status ===
|
|
248
|
+
s.status === "SUCCEEDED");
|
|
237
249
|
if (recovery) {
|
|
238
250
|
recoveryCount++;
|
|
239
251
|
evidenceHashes.push(fail.event_hash, recovery.event_hash);
|
|
@@ -242,112 +254,290 @@ export const CanHandleHttpErrors = {
|
|
|
242
254
|
if (recoveryCount === 0)
|
|
243
255
|
return [];
|
|
244
256
|
const { confidence } = compositeConfidence(recoveryCount, failed.length - recoveryCount, latestAge(httpCalls));
|
|
245
|
-
return [
|
|
246
|
-
|
|
257
|
+
return [
|
|
258
|
+
{
|
|
259
|
+
claimType: "cg:CanHandleHttpErrors",
|
|
247
260
|
confidence,
|
|
248
261
|
evidenceHashes,
|
|
249
|
-
}
|
|
262
|
+
},
|
|
263
|
+
];
|
|
250
264
|
},
|
|
251
265
|
};
|
|
252
266
|
// ── Platform Agent Rules (NEW — for AGENT_ACTION events) ───────────
|
|
253
267
|
export const CanCreateContent = {
|
|
254
|
-
id:
|
|
255
|
-
name:
|
|
256
|
-
description:
|
|
268
|
+
id: "cg:CanCreateContent",
|
|
269
|
+
name: "Can Create Content",
|
|
270
|
+
description: "Agent created discussions or other content on the platform",
|
|
257
271
|
evaluate(ctx) {
|
|
258
|
-
const actions = ctx.events.filter((e) => e.type ===
|
|
259
|
-
const creates = actions.filter((e) => e.data.action ===
|
|
272
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION");
|
|
273
|
+
const creates = actions.filter((e) => e.data.action === "create_discussion" || e.data.action === "create");
|
|
260
274
|
if (creates.length === 0)
|
|
261
275
|
return [];
|
|
262
|
-
const succeeded = countByStatus(creates,
|
|
276
|
+
const succeeded = countByStatus(creates, "SUCCEEDED");
|
|
263
277
|
const { confidence } = compositeConfidence(succeeded, creates.length - succeeded, latestAge(creates));
|
|
264
|
-
return [
|
|
265
|
-
|
|
278
|
+
return [
|
|
279
|
+
{
|
|
280
|
+
claimType: "cg:CanCreateContent",
|
|
266
281
|
confidence,
|
|
267
|
-
scope:
|
|
282
|
+
scope: "discussions",
|
|
268
283
|
evidenceHashes: creates.map((e) => e.event_hash),
|
|
269
|
-
}
|
|
284
|
+
},
|
|
285
|
+
];
|
|
270
286
|
},
|
|
271
287
|
};
|
|
272
288
|
export const CanEngageCommunity = {
|
|
273
|
-
id:
|
|
274
|
-
name:
|
|
275
|
-
description:
|
|
289
|
+
id: "cg:CanEngageCommunity",
|
|
290
|
+
name: "Can Engage Community",
|
|
291
|
+
description: "Agent engaged with the community through votes, comments, and subscriptions",
|
|
276
292
|
evaluate(ctx) {
|
|
277
|
-
const actions = ctx.events.filter((e) => e.type ===
|
|
278
|
-
const engagementTypes = new Set([
|
|
293
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION");
|
|
294
|
+
const engagementTypes = new Set([
|
|
295
|
+
"vote",
|
|
296
|
+
"comment",
|
|
297
|
+
"subscribe",
|
|
298
|
+
"follow",
|
|
299
|
+
"upvote",
|
|
300
|
+
"downvote",
|
|
301
|
+
]);
|
|
279
302
|
const engagements = actions.filter((e) => engagementTypes.has(e.data.action));
|
|
280
303
|
if (engagements.length === 0)
|
|
281
304
|
return [];
|
|
282
|
-
const succeeded = countByStatus(engagements,
|
|
283
|
-
const uniqueTypes = new Set(engagements.map((e) => e.data.action))
|
|
305
|
+
const succeeded = countByStatus(engagements, "SUCCEEDED");
|
|
306
|
+
const uniqueTypes = new Set(engagements.map((e) => e.data.action))
|
|
307
|
+
.size;
|
|
284
308
|
// Diversity bonus: more action types → higher confidence
|
|
285
309
|
const wilson = wilsonScoreLower(succeeded, engagements.length);
|
|
286
310
|
const diversityBonus = Math.min(0.1, uniqueTypes * 0.02);
|
|
287
311
|
const confidence = Math.min(1, wilson + diversityBonus);
|
|
288
|
-
return [
|
|
289
|
-
|
|
312
|
+
return [
|
|
313
|
+
{
|
|
314
|
+
claimType: "cg:CanEngageCommunity",
|
|
290
315
|
confidence,
|
|
291
316
|
scope: `${uniqueTypes}_types`,
|
|
292
317
|
evidenceHashes: engagements.map((e) => e.event_hash),
|
|
293
|
-
}
|
|
318
|
+
},
|
|
319
|
+
];
|
|
294
320
|
},
|
|
295
321
|
};
|
|
296
322
|
export const CanRespondToNotifications = {
|
|
297
|
-
id:
|
|
298
|
-
name:
|
|
299
|
-
description:
|
|
323
|
+
id: "cg:CanRespondToNotifications",
|
|
324
|
+
name: "Can Respond To Notifications",
|
|
325
|
+
description: "Agent processed and responded to notifications",
|
|
300
326
|
evaluate(ctx) {
|
|
301
|
-
const actions = ctx.events.filter((e) => e.type ===
|
|
302
|
-
const responses = actions.filter((e) => e.data.action ===
|
|
303
|
-
e.data.action ===
|
|
304
|
-
e.data.action ===
|
|
305
|
-
e.data.action ===
|
|
327
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION");
|
|
328
|
+
const responses = actions.filter((e) => e.data.action === "reply" ||
|
|
329
|
+
e.data.action === "respond" ||
|
|
330
|
+
e.data.action === "check_notifications" ||
|
|
331
|
+
e.data.action === "process_notification");
|
|
306
332
|
if (responses.length === 0)
|
|
307
333
|
return [];
|
|
308
|
-
const succeeded = countByStatus(responses,
|
|
334
|
+
const succeeded = countByStatus(responses, "SUCCEEDED");
|
|
309
335
|
const { confidence } = compositeConfidence(succeeded, responses.length - succeeded, latestAge(responses));
|
|
310
|
-
return [
|
|
311
|
-
|
|
336
|
+
return [
|
|
337
|
+
{
|
|
338
|
+
claimType: "cg:CanRespondToNotifications",
|
|
312
339
|
confidence,
|
|
313
340
|
evidenceHashes: responses.map((e) => e.event_hash),
|
|
314
|
-
}
|
|
341
|
+
},
|
|
342
|
+
];
|
|
315
343
|
},
|
|
316
344
|
};
|
|
317
345
|
export const CanMakeDecisions = {
|
|
318
|
-
id:
|
|
319
|
-
name:
|
|
320
|
-
description:
|
|
346
|
+
id: "cg:CanMakeDecisions",
|
|
347
|
+
name: "Can Make Decisions",
|
|
348
|
+
description: "Agent logged decisions with reasoning",
|
|
321
349
|
evaluate(ctx) {
|
|
322
|
-
const actions = ctx.events.filter((e) => e.type ===
|
|
350
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION");
|
|
323
351
|
const withReasoning = actions.filter((e) => e.data.reasoning_hash != null);
|
|
324
352
|
if (withReasoning.length === 0)
|
|
325
353
|
return [];
|
|
326
354
|
const total = actions.length;
|
|
327
355
|
const { confidence } = compositeConfidence(withReasoning.length, total - withReasoning.length, latestAge(withReasoning));
|
|
328
|
-
return [
|
|
329
|
-
|
|
356
|
+
return [
|
|
357
|
+
{
|
|
358
|
+
claimType: "cg:CanMakeDecisions",
|
|
330
359
|
confidence,
|
|
331
360
|
scope: `${withReasoning.length}_of_${total}`,
|
|
332
361
|
evidenceHashes: withReasoning.map((e) => e.event_hash),
|
|
333
|
-
}
|
|
362
|
+
},
|
|
363
|
+
];
|
|
334
364
|
},
|
|
335
365
|
};
|
|
336
366
|
export const IsConsistentlyActive = {
|
|
337
|
-
id:
|
|
338
|
-
name:
|
|
339
|
-
description:
|
|
367
|
+
id: "cg:IsConsistentlyActive",
|
|
368
|
+
name: "Is Consistently Active",
|
|
369
|
+
description: "Agent performed actions throughout the session window",
|
|
340
370
|
evaluate(ctx) {
|
|
341
|
-
const actions = ctx.events.filter((e) => e.type ===
|
|
371
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION" && e.status === "SUCCEEDED");
|
|
342
372
|
if (actions.length < 2)
|
|
343
373
|
return [];
|
|
344
374
|
const { confidence } = compositeConfidence(actions.length, 0, latestAge(actions));
|
|
345
|
-
return [
|
|
346
|
-
|
|
375
|
+
return [
|
|
376
|
+
{
|
|
377
|
+
claimType: "cg:IsConsistentlyActive",
|
|
347
378
|
confidence,
|
|
348
379
|
scope: `${actions.length}_actions`,
|
|
349
380
|
evidenceHashes: actions.map((e) => e.event_hash),
|
|
350
|
-
}
|
|
381
|
+
},
|
|
382
|
+
];
|
|
383
|
+
},
|
|
384
|
+
};
|
|
385
|
+
// ── Web & Browsing Rules (NEW — for WEB_SEARCH / WEB_FETCH / BROWSER_ACTION) ─
|
|
386
|
+
export const CanBrowseWeb = {
|
|
387
|
+
id: "cg:CanBrowseWeb",
|
|
388
|
+
name: "Can Browse Web",
|
|
389
|
+
description: "Agent successfully browsed the web (search, fetch, or browser automation)",
|
|
390
|
+
evaluate(ctx) {
|
|
391
|
+
const webEvents = ctx.events.filter((e) => e.type === "WEB_SEARCH" ||
|
|
392
|
+
e.type === "WEB_FETCH" ||
|
|
393
|
+
e.type === "BROWSER_ACTION");
|
|
394
|
+
const succeeded = webEvents.filter((e) => e.status === "SUCCEEDED");
|
|
395
|
+
if (succeeded.length < 2)
|
|
396
|
+
return [];
|
|
397
|
+
// Scope to most-visited host
|
|
398
|
+
const hostCounts = new Map();
|
|
399
|
+
for (const e of succeeded) {
|
|
400
|
+
const host = e.data.host_display || "unknown";
|
|
401
|
+
hostCounts.set(host, (hostCounts.get(host) || 0) + 1);
|
|
402
|
+
}
|
|
403
|
+
const topHost = [...hostCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];
|
|
404
|
+
const { confidence } = compositeConfidence(succeeded.length, webEvents.length - succeeded.length, latestAge(succeeded));
|
|
405
|
+
return [
|
|
406
|
+
{
|
|
407
|
+
claimType: "cg:CanBrowseWeb",
|
|
408
|
+
confidence,
|
|
409
|
+
scope: topHost,
|
|
410
|
+
evidenceHashes: succeeded.map((e) => e.event_hash),
|
|
411
|
+
},
|
|
412
|
+
];
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
export const CanSearchWeb = {
|
|
416
|
+
id: "cg:CanSearchWeb",
|
|
417
|
+
name: "Can Search Web",
|
|
418
|
+
description: "Agent formulated and executed web search queries",
|
|
419
|
+
evaluate(ctx) {
|
|
420
|
+
const searches = ctx.events.filter((e) => e.type === "WEB_SEARCH");
|
|
421
|
+
const succeeded = searches.filter((e) => e.status === "SUCCEEDED");
|
|
422
|
+
if (succeeded.length < 2)
|
|
423
|
+
return [];
|
|
424
|
+
// Scope to search provider if consistent
|
|
425
|
+
const providers = [
|
|
426
|
+
...new Set(succeeded
|
|
427
|
+
.map((e) => e.data.provider)
|
|
428
|
+
.filter(Boolean)),
|
|
429
|
+
];
|
|
430
|
+
const { confidence } = compositeConfidence(succeeded.length, searches.length - succeeded.length, latestAge(succeeded));
|
|
431
|
+
return [
|
|
432
|
+
{
|
|
433
|
+
claimType: "cg:CanSearchWeb",
|
|
434
|
+
confidence,
|
|
435
|
+
scope: providers.length === 1 ? providers[0] : undefined,
|
|
436
|
+
evidenceHashes: succeeded.map((e) => e.event_hash),
|
|
437
|
+
},
|
|
438
|
+
];
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
// ── Messaging Rules (NEW — for MESSAGE_SEND events) ─────────────────
|
|
442
|
+
export const CanSendMessages = {
|
|
443
|
+
id: "cg:CanSendMessages",
|
|
444
|
+
name: "Can Send Messages",
|
|
445
|
+
description: "Agent sent messages across chat platforms",
|
|
446
|
+
evaluate(ctx) {
|
|
447
|
+
const msgs = ctx.events.filter((e) => e.type === "MESSAGE_SEND");
|
|
448
|
+
const succeeded = msgs.filter((e) => e.status === "SUCCEEDED");
|
|
449
|
+
if (succeeded.length < 2)
|
|
450
|
+
return [];
|
|
451
|
+
// One claim per channel platform
|
|
452
|
+
const channels = new Map();
|
|
453
|
+
for (const e of succeeded) {
|
|
454
|
+
const ch = e.data.channel || "unknown";
|
|
455
|
+
if (!channels.has(ch))
|
|
456
|
+
channels.set(ch, []);
|
|
457
|
+
channels.get(ch).push(e);
|
|
458
|
+
}
|
|
459
|
+
return [...channels.entries()].map(([ch, events]) => {
|
|
460
|
+
const totalForCh = msgs.filter((e) => (e.data.channel || "unknown") === ch).length;
|
|
461
|
+
const { confidence } = compositeConfidence(events.length, totalForCh - events.length, latestAge(events));
|
|
462
|
+
return {
|
|
463
|
+
claimType: "cg:CanSendMessages",
|
|
464
|
+
confidence,
|
|
465
|
+
scope: ch,
|
|
466
|
+
evidenceHashes: events.map((e) => e.event_hash),
|
|
467
|
+
};
|
|
468
|
+
});
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
// ── Document Analysis Rules (NEW — for DOCUMENT_ANALYSIS events) ────
|
|
472
|
+
export const CanAnalyzeDocuments = {
|
|
473
|
+
id: "cg:CanAnalyzeDocuments",
|
|
474
|
+
name: "Can Analyze Documents",
|
|
475
|
+
description: "Agent analyzed PDF or image documents",
|
|
476
|
+
evaluate(ctx) {
|
|
477
|
+
const docs = ctx.events.filter((e) => e.type === "DOCUMENT_ANALYSIS");
|
|
478
|
+
const succeeded = docs.filter((e) => e.status === "SUCCEEDED");
|
|
479
|
+
if (succeeded.length < 2)
|
|
480
|
+
return [];
|
|
481
|
+
// One claim per doc type
|
|
482
|
+
const types = new Map();
|
|
483
|
+
for (const e of succeeded) {
|
|
484
|
+
const dt = e.data.doc_type || "unknown";
|
|
485
|
+
if (!types.has(dt))
|
|
486
|
+
types.set(dt, []);
|
|
487
|
+
types.get(dt).push(e);
|
|
488
|
+
}
|
|
489
|
+
return [...types.entries()].map(([dt, events]) => {
|
|
490
|
+
const totalForType = docs.filter((e) => (e.data.doc_type || "unknown") === dt).length;
|
|
491
|
+
const { confidence } = compositeConfidence(events.length, totalForType - events.length, latestAge(events));
|
|
492
|
+
return {
|
|
493
|
+
claimType: "cg:CanAnalyzeDocuments",
|
|
494
|
+
confidence,
|
|
495
|
+
scope: dt,
|
|
496
|
+
evidenceHashes: events.map((e) => e.event_hash),
|
|
497
|
+
};
|
|
498
|
+
});
|
|
499
|
+
},
|
|
500
|
+
};
|
|
501
|
+
// ── Multi-Agent Coordination Rules (NEW — for MULTI_AGENT_ACTION events) ─
|
|
502
|
+
export const CanCoordinateAgents = {
|
|
503
|
+
id: "cg:CanCoordinateAgents",
|
|
504
|
+
name: "Can Coordinate Agents",
|
|
505
|
+
description: "Agent spawned or communicated with other agents",
|
|
506
|
+
evaluate(ctx) {
|
|
507
|
+
const agentActions = ctx.events.filter((e) => e.type === "MULTI_AGENT_ACTION" &&
|
|
508
|
+
(e.data.action === "spawn" || e.data.action === "send"));
|
|
509
|
+
const succeeded = agentActions.filter((e) => e.status === "SUCCEEDED");
|
|
510
|
+
if (succeeded.length < 2)
|
|
511
|
+
return [];
|
|
512
|
+
const { confidence } = compositeConfidence(succeeded.length, agentActions.length - succeeded.length, latestAge(succeeded));
|
|
513
|
+
return [
|
|
514
|
+
{
|
|
515
|
+
claimType: "cg:CanCoordinateAgents",
|
|
516
|
+
confidence,
|
|
517
|
+
evidenceHashes: succeeded.map((e) => e.event_hash),
|
|
518
|
+
},
|
|
519
|
+
];
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
// ── Verified Actions Rule (NEW — for server-verified AGENT_ACTION events) ─
|
|
523
|
+
export const HasVerifiedActions = {
|
|
524
|
+
id: "cg:HasVerifiedActions",
|
|
525
|
+
name: "Has Verified Actions",
|
|
526
|
+
description: "Agent has server-verified platform actions (auto-logged, not self-reported)",
|
|
527
|
+
evaluate(ctx) {
|
|
528
|
+
const actions = ctx.events.filter((e) => e.type === "AGENT_ACTION");
|
|
529
|
+
const verified = actions.filter((e) => e.data.source === "auto");
|
|
530
|
+
if (verified.length === 0)
|
|
531
|
+
return [];
|
|
532
|
+
const { confidence } = compositeConfidence(verified.length, 0, latestAge(verified));
|
|
533
|
+
return [
|
|
534
|
+
{
|
|
535
|
+
claimType: "cg:HasVerifiedActions",
|
|
536
|
+
confidence,
|
|
537
|
+
scope: `${verified.length}_of_${actions.length}_verified`,
|
|
538
|
+
evidenceHashes: verified.map((e) => e.event_hash),
|
|
539
|
+
},
|
|
540
|
+
];
|
|
351
541
|
},
|
|
352
542
|
};
|
|
353
543
|
/** All OpenClaw rules for easy registration */
|
|
@@ -368,5 +558,16 @@ export const openclawRules = [
|
|
|
368
558
|
CanRespondToNotifications,
|
|
369
559
|
CanMakeDecisions,
|
|
370
560
|
IsConsistentlyActive,
|
|
561
|
+
// Web & browsing rules (fire for WEB_SEARCH / WEB_FETCH / BROWSER_ACTION events)
|
|
562
|
+
CanBrowseWeb,
|
|
563
|
+
CanSearchWeb,
|
|
564
|
+
// Messaging rules (fire for MESSAGE_SEND events)
|
|
565
|
+
CanSendMessages,
|
|
566
|
+
// Document analysis rules (fire for DOCUMENT_ANALYSIS events)
|
|
567
|
+
CanAnalyzeDocuments,
|
|
568
|
+
// Multi-agent coordination rules (fire for MULTI_AGENT_ACTION events)
|
|
569
|
+
CanCoordinateAgents,
|
|
570
|
+
// Trust signal rules (fire for verified AGENT_ACTION events)
|
|
571
|
+
HasVerifiedActions,
|
|
371
572
|
];
|
|
372
573
|
//# sourceMappingURL=openclaw-rules.js.map
|