@clawtrail/context-graph-openclaw 0.7.4 → 0.8.0

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.
Files changed (79) hide show
  1. package/README.md +64 -56
  2. package/dist/OpenClawAdapter.d.ts +6 -6
  3. package/dist/OpenClawAdapter.d.ts.map +1 -1
  4. package/dist/OpenClawAdapter.js +46 -36
  5. package/dist/OpenClawAdapter.js.map +1 -1
  6. package/dist/detectors/BuildDetector.js +11 -11
  7. package/dist/detectors/HttpDetector.d.ts.map +1 -1
  8. package/dist/detectors/HttpDetector.js +20 -17
  9. package/dist/detectors/HttpDetector.js.map +1 -1
  10. package/dist/detectors/TestDetector.js +9 -9
  11. package/dist/hooks/lifecycle.d.ts +1 -1
  12. package/dist/hooks/lifecycle.js +4 -4
  13. package/dist/hooks/llmOutput.d.ts +2 -2
  14. package/dist/hooks/llmOutput.js +5 -5
  15. package/dist/hooks/toolCall.d.ts +3 -3
  16. package/dist/hooks/toolCall.d.ts.map +1 -1
  17. package/dist/hooks/toolCall.js +4 -4
  18. package/dist/hooks/toolCall.js.map +1 -1
  19. package/dist/index.d.ts +29 -29
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +18 -18
  22. package/dist/index.js.map +1 -1
  23. package/dist/mappers/MapperRegistry.d.ts +4 -0
  24. package/dist/mappers/MapperRegistry.d.ts.map +1 -1
  25. package/dist/mappers/MapperRegistry.js +8 -0
  26. package/dist/mappers/MapperRegistry.js.map +1 -1
  27. package/dist/mappers/browser.d.ts +11 -0
  28. package/dist/mappers/browser.d.ts.map +1 -0
  29. package/dist/mappers/browser.js +66 -0
  30. package/dist/mappers/browser.js.map +1 -0
  31. package/dist/mappers/document.d.ts +7 -0
  32. package/dist/mappers/document.d.ts.map +1 -0
  33. package/dist/mappers/document.js +49 -0
  34. package/dist/mappers/document.js.map +1 -0
  35. package/dist/mappers/fallback.d.ts +1 -1
  36. package/dist/mappers/fallback.js +3 -3
  37. package/dist/mappers/fs.d.ts +1 -1
  38. package/dist/mappers/fs.d.ts.map +1 -1
  39. package/dist/mappers/fs.js +11 -11
  40. package/dist/mappers/fs.js.map +1 -1
  41. package/dist/mappers/git.d.ts +1 -1
  42. package/dist/mappers/git.d.ts.map +1 -1
  43. package/dist/mappers/git.js +21 -14
  44. package/dist/mappers/git.js.map +1 -1
  45. package/dist/mappers/message.d.ts +11 -0
  46. package/dist/mappers/message.d.ts.map +1 -0
  47. package/dist/mappers/message.js +72 -0
  48. package/dist/mappers/message.js.map +1 -0
  49. package/dist/mappers/session.d.ts +12 -0
  50. package/dist/mappers/session.d.ts.map +1 -0
  51. package/dist/mappers/session.js +71 -0
  52. package/dist/mappers/session.js.map +1 -0
  53. package/dist/mappers/shell.d.ts +4 -4
  54. package/dist/mappers/shell.d.ts.map +1 -1
  55. package/dist/mappers/shell.js +17 -15
  56. package/dist/mappers/shell.js.map +1 -1
  57. package/dist/mappers/web.d.ts +11 -0
  58. package/dist/mappers/web.d.ts.map +1 -0
  59. package/dist/mappers/web.js +89 -0
  60. package/dist/mappers/web.js.map +1 -0
  61. package/dist/register.d.ts.map +1 -1
  62. package/dist/register.js +123 -4
  63. package/dist/register.js.map +1 -1
  64. package/dist/rules/openclaw-rules.d.ts +7 -1
  65. package/dist/rules/openclaw-rules.d.ts.map +1 -1
  66. package/dist/rules/openclaw-rules.js +321 -120
  67. package/dist/rules/openclaw-rules.js.map +1 -1
  68. package/dist/tools/status.d.ts +1 -1
  69. package/dist/tools/status.js +3 -3
  70. package/dist/tools/summarize.d.ts +1 -1
  71. package/dist/tools/summarize.d.ts.map +1 -1
  72. package/dist/tools/summarize.js +5 -5
  73. package/dist/tools/summarize.js.map +1 -1
  74. package/dist/util/hash.d.ts +3 -1
  75. package/dist/util/hash.d.ts.map +1 -1
  76. package/dist/util/hash.js +64 -43
  77. package/dist/util/hash.js.map +1 -1
  78. package/openclaw.plugin.json +5 -1
  79. package/package.json +6 -4
@@ -1,5 +1,5 @@
1
- import { compositeConfidence, wilsonScoreLower } from '@clawtrail/context-graph';
2
- import { extensionToLanguage } from '../util/hash.js';
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: 'cg:CanFixBuild',
18
- name: 'Can Fix Build',
19
- description: 'Agent recovered a failing build within the same session',
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 === '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);
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
- claimType: 'cg:CanFixBuild',
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: 'cg:CanFixTests',
43
- name: 'Can Fix Tests',
44
- description: 'Agent recovered failing tests within the same session',
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 === 'TEST_RUN');
47
- const failed = testRuns.filter((e) => e.status === 'FAILED' ||
48
- (e.data.failed > 0));
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
- claimType: 'cg:CanFixTests',
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: 'cg:CanRunTests',
69
- name: 'Can Run Tests',
70
- description: 'Agent successfully ran tests multiple times',
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 === 'TEST_RUN' && e.status === 'SUCCEEDED');
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 === 'TEST_RUN');
76
- const frameworks = [...new Set(successful.map((e) => e.data.framework))];
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 === 'SUCCEEDED').length;
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: 'cg:CanRunTests',
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: 'cg:CanRecoverFromError',
92
- name: 'Can Recover From Error',
93
- description: 'Agent recovered from an error by succeeding on the same artifact',
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 === 'ERROR');
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 === 'SUCCEEDED');
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
- claimType: 'cg:CanRecoverFromError',
110
+ return [
111
+ {
112
+ claimType: "cg:CanRecoverFromError",
107
113
  confidence,
108
- evidenceHashes: recoveries.flatMap((r) => [r.error.event_hash, r.success.event_hash]),
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: 'cg:CanWrite',
114
- name: 'Can Write Code',
115
- description: 'Agent wrote files in specific languages',
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 === 'FILE_WRITE' && e.status === 'SUCCEEDED');
118
- const allWrites = ctx.events.filter((e) => e.type === 'FILE_WRITE');
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: 'cg:CanWrite',
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: 'cg:CanUseFramework',
142
- name: 'Can Use Framework',
143
- description: 'Agent used specific test/build frameworks',
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 === 'TEST_RUN')
158
+ if (e.type === "TEST_RUN")
149
159
  fw = e.data.framework;
150
- if (e.type === 'BUILD_RUN')
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, 'SUCCEEDED');
169
+ const succeeded = countByStatus(events, "SUCCEEDED");
160
170
  const { confidence } = compositeConfidence(succeeded, events.length - succeeded, latestAge(events));
161
171
  return {
162
- claimType: 'cg:CanUseFramework',
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: 'cg:CanUseTool',
172
- name: 'Can Use Tool',
173
- description: 'Agent used specific shell tools',
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 === 'SHELL_COMMAND' || e.type === 'TOOL_CALL') {
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(' ')[0];
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, 'SUCCEEDED');
198
+ const succeeded = countByStatus(events, "SUCCEEDED");
189
199
  const { confidence } = compositeConfidence(succeeded, events.length - succeeded, latestAge(events));
190
200
  return {
191
- claimType: 'cg:CanUseTool',
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: 'cg:CanCallApis',
201
- name: 'Can Call APIs',
202
- description: 'Agent successfully called HTTP APIs',
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 === 'HTTP_REQUEST');
214
+ const httpCalls = ctx.events.filter((e) => e.type === "HTTP_REQUEST");
205
215
  if (httpCalls.length < 2)
206
216
  return [];
207
- const hosts = [...new Set(httpCalls.map((e) => e.data.host_hash))];
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, 'SUCCEEDED');
222
+ const succeeded = countByStatus(hostEvents, "SUCCEEDED");
211
223
  const { confidence } = compositeConfidence(succeeded, hostEvents.length - succeeded, latestAge(hostEvents));
212
224
  return {
213
- claimType: 'cg:CanCallApis',
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: 'cg:CanHandleHttpErrors',
223
- name: 'Can Handle HTTP Errors',
224
- description: 'Agent retried or recovered from HTTP errors',
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 === 'HTTP_REQUEST');
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 === 'FAILED' || (sc !== undefined && sc >= 400);
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 === 'SUCCEEDED');
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
- claimType: 'cg:CanHandleHttpErrors',
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: 'cg:CanCreateContent',
255
- name: 'Can Create Content',
256
- description: 'Agent created discussions or other content on the platform',
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 === 'AGENT_ACTION');
259
- const creates = actions.filter((e) => e.data.action === 'create_discussion' || e.data.action === 'create');
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, 'SUCCEEDED');
276
+ const succeeded = countByStatus(creates, "SUCCEEDED");
263
277
  const { confidence } = compositeConfidence(succeeded, creates.length - succeeded, latestAge(creates));
264
- return [{
265
- claimType: 'cg:CanCreateContent',
278
+ return [
279
+ {
280
+ claimType: "cg:CanCreateContent",
266
281
  confidence,
267
- scope: 'discussions',
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: 'cg:CanEngageCommunity',
274
- name: 'Can Engage Community',
275
- description: 'Agent engaged with the community through votes, comments, and subscriptions',
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 === 'AGENT_ACTION');
278
- const engagementTypes = new Set(['vote', 'comment', 'subscribe', 'follow', 'upvote', 'downvote']);
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, 'SUCCEEDED');
283
- const uniqueTypes = new Set(engagements.map((e) => e.data.action)).size;
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
- claimType: 'cg:CanEngageCommunity',
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: 'cg:CanRespondToNotifications',
298
- name: 'Can Respond To Notifications',
299
- description: 'Agent processed and responded to notifications',
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 === 'AGENT_ACTION');
302
- const responses = actions.filter((e) => e.data.action === 'reply' ||
303
- e.data.action === 'respond' ||
304
- e.data.action === 'check_notifications' ||
305
- e.data.action === 'process_notification');
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, 'SUCCEEDED');
334
+ const succeeded = countByStatus(responses, "SUCCEEDED");
309
335
  const { confidence } = compositeConfidence(succeeded, responses.length - succeeded, latestAge(responses));
310
- return [{
311
- claimType: 'cg:CanRespondToNotifications',
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: 'cg:CanMakeDecisions',
319
- name: 'Can Make Decisions',
320
- description: 'Agent logged decisions with reasoning',
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 === 'AGENT_ACTION');
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
- claimType: 'cg:CanMakeDecisions',
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: 'cg:IsConsistentlyActive',
338
- name: 'Is Consistently Active',
339
- description: 'Agent performed actions throughout the session window',
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 === 'AGENT_ACTION' && e.status === 'SUCCEEDED');
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
- claimType: 'cg:IsConsistentlyActive',
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