@dhfpub/clawpool-admin 0.1.2 → 0.2.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 CHANGED
@@ -14,7 +14,7 @@ If you are reading the channel plugin documentation first, also read:
14
14
  ## Which Package Do I Need?
15
15
 
16
16
  - Install only `@dhfpub/clawpool` when you only need ClawPool channel transport, website onboarding, and the bundled onboarding skill
17
- - Install both `@dhfpub/clawpool` and `@dhfpub/clawpool-admin` when you want typed group governance or typed API-agent admin actions inside OpenClaw
17
+ - Install both `@dhfpub/clawpool` and `@dhfpub/clawpool-admin` when you want typed query, group governance, or typed API-agent admin actions inside OpenClaw
18
18
  - Do not install only `@dhfpub/clawpool-admin` and expect it to work alone, because it depends on the `channels.clawpool` credentials managed by `@dhfpub/clawpool`
19
19
 
20
20
  ## Install
@@ -48,7 +48,7 @@ For the channel-side setup flow, see:
48
48
  3. Enable the required tools in OpenClaw config
49
49
  4. Restart the OpenClaw gateway
50
50
 
51
- If the `tools` block is missing, the plugin may be installed and loaded, but the agent still cannot use `clawpool_group` or `clawpool_agent_admin`.
51
+ If the `tools` block is missing, the plugin may be installed and loaded, but the agent still cannot use `clawpool_query`, `clawpool_group`, or `clawpool_agent_admin`.
52
52
 
53
53
  ## Configure `channels.clawpool` First
54
54
 
@@ -79,6 +79,7 @@ To make the admin capabilities available to the OpenClaw agent, configure `tools
79
79
  "profile": "coding",
80
80
  "alsoAllow": [
81
81
  "message",
82
+ "clawpool_query",
82
83
  "clawpool_group",
83
84
  "clawpool_agent_admin"
84
85
  ],
@@ -92,6 +93,7 @@ To make the admin capabilities available to the OpenClaw agent, configure `tools
92
93
  These fields are required for the intended ClawPool group-governance workflow:
93
94
 
94
95
  - `message`: lets the agent send and coordinate messages in the group workflow
96
+ - `clawpool_query`: enables typed contact search, session search, and session message-history lookup
95
97
  - `clawpool_group`: enables typed group governance actions
96
98
  - `clawpool_agent_admin`: enables typed API-agent admin actions
97
99
  - `sessions.visibility = agent`: ensures the tool session context is visible to the agent runtime
@@ -112,6 +114,7 @@ These fields are required for the intended ClawPool group-governance workflow:
112
114
  "profile": "coding",
113
115
  "alsoAllow": [
114
116
  "message",
117
+ "clawpool_query",
115
118
  "clawpool_group",
116
119
  "clawpool_agent_admin"
117
120
  ],
@@ -134,11 +137,19 @@ openclaw clawpool-admin doctor
134
137
  Expected result:
135
138
 
136
139
  - `plugins info clawpool-admin` shows `enabled=true`, `status=loaded`
137
- - the plugin exposes `clawpool_group` and `clawpool_agent_admin`
140
+ - the plugin exposes `clawpool_query`, `clawpool_group`, and `clawpool_agent_admin`
138
141
  - `clawpool-admin doctor` can see the configured `channels.clawpool` account
139
142
 
140
143
  ## Agent Tools
141
144
 
145
+ ### `clawpool_query`
146
+
147
+ Typed query tool with these actions:
148
+
149
+ - `contact_search`
150
+ - `session_search`
151
+ - `message_history`
152
+
142
153
  ### `clawpool_group`
143
154
 
144
155
  Typed group governance tool with these actions:
@@ -148,6 +159,8 @@ Typed group governance tool with these actions:
148
159
  - `add_members`
149
160
  - `remove_members`
150
161
  - `update_member_role`
162
+ - `update_all_members_muted`
163
+ - `update_member_speaking`
151
164
  - `dissolve`
152
165
 
153
166
  ### `clawpool_agent_admin`
package/dist/index.js CHANGED
@@ -87,6 +87,32 @@ function readRequiredInt(params, key) {
87
87
  }
88
88
  return value;
89
89
  }
90
+ function readOptionalBool(params, key) {
91
+ const raw = readRawParam(params, key);
92
+ if (raw == null) {
93
+ return void 0;
94
+ }
95
+ if (typeof raw === "boolean") {
96
+ return raw;
97
+ }
98
+ if (typeof raw === "number") {
99
+ if (raw === 1) return true;
100
+ if (raw === 0) return false;
101
+ }
102
+ if (typeof raw === "string") {
103
+ const normalized = raw.trim().toLowerCase();
104
+ if (normalized === "true" || normalized === "1") return true;
105
+ if (normalized === "false" || normalized === "0") return false;
106
+ }
107
+ throw new Error(`Clawpool action ${key} must be a boolean.`);
108
+ }
109
+ function readRequiredBool(params, key) {
110
+ const value = readOptionalBool(params, key);
111
+ if (value == null) {
112
+ throw new Error(`Clawpool action requires ${key}.`);
113
+ }
114
+ return value;
115
+ }
90
116
  function ensureMemberTypes(types) {
91
117
  for (const memberType of types) {
92
118
  if (memberType !== 1 && memberType !== 2) {
@@ -99,6 +125,11 @@ function ensureMemberType(memberType) {
99
125
  throw new Error("Clawpool action member_type only supports 1 for role update.");
100
126
  }
101
127
  }
128
+ function ensureSpeakingMemberType(memberType) {
129
+ if (memberType !== 1 && memberType !== 2) {
130
+ throw new Error("Clawpool action member_type only supports 1 (human) or 2 (agent).");
131
+ }
132
+ }
102
133
  function buildGroupCreateRequest(params) {
103
134
  const name = readRequiredStringParam(params, "name");
104
135
  const memberIDs = readNumericIDArray(params, "memberIds", false);
@@ -206,6 +237,52 @@ function buildGroupDissolveRequest(params) {
206
237
  }
207
238
  };
208
239
  }
240
+ function buildGroupAllMembersMutedUpdateRequest(params) {
241
+ const sessionID = readRequiredStringParam(params, "sessionId");
242
+ const allMembersMuted = readRequiredBool(params, "allMembersMuted");
243
+ return {
244
+ actionName: "group_all_members_muted_update",
245
+ method: "POST",
246
+ path: "/sessions/speaking/all_muted",
247
+ body: {
248
+ session_id: sessionID,
249
+ all_members_muted: allMembersMuted
250
+ }
251
+ };
252
+ }
253
+ function buildGroupMemberSpeakingUpdateRequest(params) {
254
+ const sessionID = readRequiredStringParam(params, "sessionId");
255
+ const memberID = readRequiredStringParam(params, "memberId");
256
+ if (!/^\d+$/.test(memberID)) {
257
+ throw new Error("Clawpool action memberId must be numeric.");
258
+ }
259
+ const memberType = readOptionalInt(params, "memberType") ?? 1;
260
+ ensureSpeakingMemberType(memberType);
261
+ const isSpeakMuted = readOptionalBool(params, "isSpeakMuted");
262
+ const canSpeakWhenAllMuted = readOptionalBool(params, "canSpeakWhenAllMuted");
263
+ if (isSpeakMuted == null && canSpeakWhenAllMuted == null) {
264
+ throw new Error(
265
+ "Clawpool action update_member_speaking requires isSpeakMuted or canSpeakWhenAllMuted."
266
+ );
267
+ }
268
+ const body = {
269
+ session_id: sessionID,
270
+ member_id: memberID,
271
+ member_type: memberType
272
+ };
273
+ if (isSpeakMuted != null) {
274
+ body.is_speak_muted = isSpeakMuted;
275
+ }
276
+ if (canSpeakWhenAllMuted != null) {
277
+ body.can_speak_when_all_muted = canSpeakWhenAllMuted;
278
+ }
279
+ return {
280
+ actionName: "group_member_speaking_update",
281
+ method: "POST",
282
+ path: "/sessions/members/speaking",
283
+ body
284
+ };
285
+ }
209
286
  function buildGroupDetailReadRequest(params) {
210
287
  const sessionID = readRequiredStringParam(params, "sessionId");
211
288
  return {
@@ -217,6 +294,66 @@ function buildGroupDetailReadRequest(params) {
217
294
  }
218
295
  };
219
296
  }
297
+ function buildContactSearchRequest(params) {
298
+ const keyword = readRequiredStringParam(params, "keyword");
299
+ const limit = readOptionalInt(params, "limit");
300
+ const offset = readOptionalInt(params, "offset");
301
+ const query = {
302
+ keyword
303
+ };
304
+ if (limit != null) {
305
+ query.limit = String(limit);
306
+ }
307
+ if (offset != null) {
308
+ query.offset = String(offset);
309
+ }
310
+ return {
311
+ actionName: "contact_search",
312
+ method: "GET",
313
+ path: "/contacts/search",
314
+ query
315
+ };
316
+ }
317
+ function buildSessionSearchRequest(params) {
318
+ const keyword = readRequiredStringParam(params, "keyword");
319
+ const limit = readOptionalInt(params, "limit");
320
+ const offset = readOptionalInt(params, "offset");
321
+ const query = {
322
+ keyword
323
+ };
324
+ if (limit != null) {
325
+ query.limit = String(limit);
326
+ }
327
+ if (offset != null) {
328
+ query.offset = String(offset);
329
+ }
330
+ return {
331
+ actionName: "session_search",
332
+ method: "GET",
333
+ path: "/sessions/search",
334
+ query
335
+ };
336
+ }
337
+ function buildMessageHistoryRequest(params) {
338
+ const sessionID = readRequiredStringParam(params, "sessionId");
339
+ const beforeID = readStringParam(params, "beforeId");
340
+ const limit = readOptionalInt(params, "limit");
341
+ const query = {
342
+ session_id: sessionID
343
+ };
344
+ if (beforeID) {
345
+ query.before_id = beforeID;
346
+ }
347
+ if (limit != null) {
348
+ query.limit = String(limit);
349
+ }
350
+ return {
351
+ actionName: "message_history",
352
+ method: "GET",
353
+ path: "/messages/history",
354
+ query
355
+ };
356
+ }
220
357
  function buildAgentAPICreateRequest(params) {
221
358
  const agentName = readRequiredStringParam(params, "agentName");
222
359
  if (!AGENT_NAME_RE.test(agentName)) {
@@ -238,6 +375,12 @@ function buildAgentAPICreateRequest(params) {
238
375
  }
239
376
  function buildAgentHTTPRequest(action, params) {
240
377
  switch (action) {
378
+ case "contact_search":
379
+ return buildContactSearchRequest(params);
380
+ case "session_search":
381
+ return buildSessionSearchRequest(params);
382
+ case "message_history":
383
+ return buildMessageHistoryRequest(params);
241
384
  case "group_create":
242
385
  return buildGroupCreateRequest(params);
243
386
  case "group_member_add":
@@ -246,6 +389,10 @@ function buildAgentHTTPRequest(action, params) {
246
389
  return buildGroupMemberRemoveRequest(params);
247
390
  case "group_member_role_update":
248
391
  return buildGroupMemberRoleUpdateRequest(params);
392
+ case "group_all_members_muted_update":
393
+ return buildGroupAllMembersMutedUpdateRequest(params);
394
+ case "group_member_speaking_update":
395
+ return buildGroupMemberSpeakingUpdateRequest(params);
249
396
  case "group_dissolve":
250
397
  return buildGroupDissolveRequest(params);
251
398
  case "group_detail_read":
@@ -668,6 +815,10 @@ function mapGroupActionToRequestAction(action) {
668
815
  return "group_member_remove";
669
816
  case "update_member_role":
670
817
  return "group_member_role_update";
818
+ case "update_all_members_muted":
819
+ return "group_all_members_muted_update";
820
+ case "update_member_speaking":
821
+ return "group_member_speaking_update";
671
822
  case "dissolve":
672
823
  return "group_dissolve";
673
824
  default:
@@ -770,6 +921,35 @@ var ClawpoolGroupToolSchema = {
770
921
  },
771
922
  required: ["action", "sessionId", "memberId", "role"]
772
923
  },
924
+ {
925
+ type: "object",
926
+ additionalProperties: false,
927
+ properties: {
928
+ action: { const: "update_all_members_muted" },
929
+ accountId: { type: "string", minLength: 1 },
930
+ sessionId: { type: "string", minLength: 1 },
931
+ allMembersMuted: { type: "boolean" }
932
+ },
933
+ required: ["action", "sessionId", "allMembersMuted"]
934
+ },
935
+ {
936
+ type: "object",
937
+ additionalProperties: false,
938
+ properties: {
939
+ action: { const: "update_member_speaking" },
940
+ accountId: { type: "string", minLength: 1 },
941
+ sessionId: { type: "string", minLength: 1 },
942
+ memberId: numericIdSchema,
943
+ memberType: { type: "integer", enum: [1, 2] },
944
+ isSpeakMuted: { type: "boolean" },
945
+ canSpeakWhenAllMuted: { type: "boolean" }
946
+ },
947
+ required: ["action", "sessionId", "memberId"],
948
+ anyOf: [
949
+ { required: ["isSpeakMuted"] },
950
+ { required: ["canSpeakWhenAllMuted"] }
951
+ ]
952
+ },
773
953
  {
774
954
  type: "object",
775
955
  additionalProperties: false,
@@ -805,6 +985,113 @@ function createClawpoolGroupTool(api) {
805
985
  };
806
986
  }
807
987
 
988
+ // src/query-service.ts
989
+ function mapQueryActionToRequestAction(action) {
990
+ switch (action) {
991
+ case "contact_search":
992
+ return "contact_search";
993
+ case "session_search":
994
+ return "session_search";
995
+ case "message_history":
996
+ return "message_history";
997
+ default:
998
+ action;
999
+ throw new Error(`Unsupported Clawpool query action: ${String(action)}`);
1000
+ }
1001
+ }
1002
+ async function runClawpoolQueryAction(params) {
1003
+ const account = resolveClawpoolAccount({
1004
+ cfg: params.cfg,
1005
+ accountId: params.toolParams.accountId
1006
+ });
1007
+ if (!account.enabled) {
1008
+ throw new Error(`Clawpool account "${account.accountId}" is disabled.`);
1009
+ }
1010
+ if (!account.configured) {
1011
+ throw new Error(`Clawpool account "${account.accountId}" is not configured.`);
1012
+ }
1013
+ const requestAction = mapQueryActionToRequestAction(params.toolParams.action);
1014
+ const request = buildAgentHTTPRequest(requestAction, params.toolParams);
1015
+ const data = await callAgentAPI({
1016
+ account,
1017
+ actionName: request.actionName,
1018
+ method: request.method,
1019
+ path: request.path,
1020
+ query: request.query,
1021
+ body: request.body
1022
+ });
1023
+ return {
1024
+ ok: true,
1025
+ accountId: account.accountId,
1026
+ action: params.toolParams.action,
1027
+ data
1028
+ };
1029
+ }
1030
+
1031
+ // src/query-tool.ts
1032
+ var ClawpoolQueryToolSchema = {
1033
+ oneOf: [
1034
+ {
1035
+ type: "object",
1036
+ additionalProperties: false,
1037
+ properties: {
1038
+ action: { const: "contact_search" },
1039
+ accountId: { type: "string", minLength: 1 },
1040
+ keyword: { type: "string", minLength: 1 },
1041
+ limit: { type: "integer", minimum: 1 },
1042
+ offset: { type: "integer", minimum: 0 }
1043
+ },
1044
+ required: ["action", "keyword"]
1045
+ },
1046
+ {
1047
+ type: "object",
1048
+ additionalProperties: false,
1049
+ properties: {
1050
+ action: { const: "session_search" },
1051
+ accountId: { type: "string", minLength: 1 },
1052
+ keyword: { type: "string", minLength: 1 },
1053
+ limit: { type: "integer", minimum: 1 },
1054
+ offset: { type: "integer", minimum: 0 }
1055
+ },
1056
+ required: ["action", "keyword"]
1057
+ },
1058
+ {
1059
+ type: "object",
1060
+ additionalProperties: false,
1061
+ properties: {
1062
+ action: { const: "message_history" },
1063
+ accountId: { type: "string", minLength: 1 },
1064
+ sessionId: { type: "string", minLength: 1 },
1065
+ beforeId: { type: "string", pattern: "^[0-9]+$" },
1066
+ limit: { type: "integer", minimum: 1 }
1067
+ },
1068
+ required: ["action", "sessionId"]
1069
+ }
1070
+ ]
1071
+ };
1072
+ function createClawpoolQueryTool(api) {
1073
+ return {
1074
+ name: "clawpool_query",
1075
+ label: "Clawpool Query",
1076
+ description: "Search Clawpool contacts and sessions, or read session message history through typed query operations.",
1077
+ parameters: ClawpoolQueryToolSchema,
1078
+ async execute(_toolCallId, params) {
1079
+ try {
1080
+ return jsonToolResult(
1081
+ await runClawpoolQueryAction({
1082
+ cfg: api.config,
1083
+ toolParams: params
1084
+ })
1085
+ );
1086
+ } catch (err) {
1087
+ return jsonToolResult({
1088
+ error: err instanceof Error ? err.message : String(err)
1089
+ });
1090
+ }
1091
+ }
1092
+ };
1093
+ }
1094
+
808
1095
  // index.ts
809
1096
  var plugin = {
810
1097
  id: "clawpool-admin",
@@ -812,6 +1099,7 @@ var plugin = {
812
1099
  description: "Typed optional admin tools and operator CLI for Clawpool",
813
1100
  configSchema: emptyPluginConfigSchema(),
814
1101
  register(api) {
1102
+ api.registerTool(createClawpoolQueryTool(api), { optional: true });
815
1103
  api.registerTool(createClawpoolGroupTool(api), { optional: true });
816
1104
  api.registerTool(createClawpoolAgentAdminTool(api), { optional: true });
817
1105
  api.registerCli(({ program }) => registerClawpoolAdminCli({ api, program }), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhfpub/clawpool-admin",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "OpenClaw admin tools plugin for ClawPool",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,7 +11,7 @@ This skill is about tool selection and guardrails, not protocol bridging.
11
11
  ## Workflow
12
12
 
13
13
  1. Parse the user request into one action:
14
- `create`, `detail`, `add_members`, `remove_members`, `update_member_role`, or `dissolve`.
14
+ `create`, `detail`, `add_members`, `remove_members`, `update_member_role`, `update_all_members_muted`, `update_member_speaking`, or `dissolve`.
15
15
  2. Validate required fields before any call.
16
16
  3. Call `clawpool_group` exactly once per business action.
17
17
  4. Classify failures by HTTP/BizCode and return exact remediation.
@@ -23,13 +23,13 @@ This skill is about tool selection and guardrails, not protocol bridging.
23
23
  For Clawpool group governance, always call:
24
24
 
25
25
  1. Tool: `clawpool_group`
26
- 2. `action`: one of `create`, `detail`, `add_members`, `remove_members`, `update_member_role`, `dissolve`
26
+ 2. `action`: one of `create`, `detail`, `add_members`, `remove_members`, `update_member_role`, `update_all_members_muted`, `update_member_speaking`, `dissolve`
27
27
  3. `accountId`: optional; include it when the configured account is ambiguous
28
28
 
29
29
  Rules:
30
30
 
31
31
  1. Pass business parameters with their exact typed field names.
32
- 2. Use `sessionId`, `memberIds`, `memberTypes`, `memberId`, `memberType`, and `role` explicitly.
32
+ 2. Use `sessionId`, `memberIds`, `memberTypes`, `memberId`, `memberType`, `role`, `allMembersMuted`, `isSpeakMuted`, and `canSpeakWhenAllMuted` explicitly.
33
33
  3. Do not invent aliases or fallback fields.
34
34
  4. Keep one tool call per action for audit clarity.
35
35
 
@@ -87,6 +87,32 @@ Guardrails:
87
87
  1. Only use `memberType=1` for role updates.
88
88
  2. Never guess a role value; confirm when unclear.
89
89
 
90
+ ### update_all_members_muted
91
+
92
+ Required input:
93
+
94
+ 1. `sessionId`
95
+ 2. `allMembersMuted`
96
+
97
+ Guardrails:
98
+
99
+ 1. Only use this for group-wide mute state changes.
100
+ 2. Never guess the desired mute state from vague wording; confirm whether the user wants to enable or disable all-member mute.
101
+
102
+ ### update_member_speaking
103
+
104
+ Required input:
105
+
106
+ 1. `sessionId`
107
+ 2. `memberId`
108
+ 3. At least one of `isSpeakMuted` or `canSpeakWhenAllMuted`
109
+
110
+ Guardrails:
111
+
112
+ 1. Only use `memberType=1` or `memberType=2`.
113
+ 2. Do not send an empty speaking update; at least one speaking field must be explicit.
114
+ 3. If the target member is ambiguous, ask the user to confirm the exact member first.
115
+
90
116
  ### detail / dissolve
91
117
 
92
118
  Required input:
@@ -109,7 +135,7 @@ Required input:
109
135
  ## Response Style
110
136
 
111
137
  1. State action result first.
112
- 2. Include key identifiers (`session_id`, member count) when successful.
138
+ 2. Include key identifiers (`session_id`, member count, mute state) when successful.
113
139
  3. Include exact remediation when failed.
114
140
  4. Never hide scope or auth errors behind generic wording.
115
141
 
@@ -29,6 +29,8 @@ Use the native `clawpool_group` tool with typed fields:
29
29
  | `add_members` | `group_member_add` | `sessionId`, `memberIds` |
30
30
  | `remove_members` | `group_member_remove` | `sessionId`, `memberIds` |
31
31
  | `update_member_role` | `group_member_role_update` | `sessionId`, `memberId`, `role` |
32
+ | `update_all_members_muted` | `group_all_members_muted_update` | `sessionId`, `allMembersMuted` |
33
+ | `update_member_speaking` | `group_member_speaking_update` | `sessionId`, `memberId`, `isSpeakMuted` or `canSpeakWhenAllMuted` |
32
34
  | `dissolve` | `group_dissolve` | `sessionId` |
33
35
 
34
36
  ## Payload Templates
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: clawpool-query
3
+ description: Use the typed `clawpool_query` tool for Clawpool contact search, session search, and session message history lookup. Trigger when users ask to find contacts, locate a conversation, or inspect recent messages in a known session.
4
+ ---
5
+
6
+ # Clawpool Query
7
+
8
+ Use the `clawpool_query` tool for read-only Clawpool lookup actions.
9
+ This skill is only for querying existing contacts, sessions, and message history.
10
+
11
+ ## Workflow
12
+
13
+ 1. Parse the user request into one action:
14
+ `contact_search`, `session_search`, or `message_history`.
15
+ 2. Validate required fields before any tool call.
16
+ 3. Call `clawpool_query` exactly once per business action.
17
+ 4. If the user wants message history but no `sessionId` is known, locate the target session first through `session_search` or ask the user for a precise target.
18
+ 5. Return exact remediation for scope, auth, and parameter failures.
19
+
20
+ ## Tool Contract
21
+
22
+ For Clawpool query actions, always call:
23
+
24
+ 1. Tool: `clawpool_query`
25
+ 2. `action`: one of `contact_search`, `session_search`, or `message_history`
26
+ 3. `accountId`: optional; include it when the configured account is ambiguous
27
+
28
+ Rules:
29
+
30
+ 1. Pass query parameters with their exact typed field names.
31
+ 2. Use `keyword` for search actions.
32
+ 3. Use `sessionId`, `beforeId`, and `limit` explicitly for message history.
33
+ 4. Never invent a `sessionId`. Resolve it from context, from a previous tool result, or ask the user.
34
+ 5. Keep one tool call per action for audit clarity.
35
+
36
+ ## Action Contracts
37
+
38
+ ### contact_search
39
+
40
+ Purpose: search the owner's Clawpool contact directory.
41
+
42
+ Required input:
43
+
44
+ 1. `keyword` (non-empty string)
45
+
46
+ Optional input:
47
+
48
+ 1. `limit`
49
+ 2. `offset`
50
+
51
+ Guardrails:
52
+
53
+ 1. Use this when the user is trying to find a person or active agent by display name, remark, nickname, username, or agent name.
54
+ 2. Do not jump directly to session history from a vague contact hint; resolve the contact or session first.
55
+
56
+ ### session_search
57
+
58
+ Purpose: search the owner's visible sessions by final display title.
59
+
60
+ Required input:
61
+
62
+ 1. `keyword` (non-empty string)
63
+
64
+ Optional input:
65
+
66
+ 1. `limit`
67
+ 2. `offset`
68
+
69
+ Guardrails:
70
+
71
+ 1. Use this when the user describes a conversation by session title, group name, or known list title.
72
+ 2. If multiple sessions match, present the candidates and let the user choose before reading history.
73
+
74
+ ### message_history
75
+
76
+ Purpose: read recent message history from a known session.
77
+
78
+ Required input:
79
+
80
+ 1. `sessionId`
81
+
82
+ Optional input:
83
+
84
+ 1. `beforeId`
85
+ 2. `limit`
86
+
87
+ Guardrails:
88
+
89
+ 1. Only call this after the target session is unambiguous.
90
+ 2. Use `beforeId` only for older-page pagination.
91
+ 3. Do not claim to have full history if only one page was fetched.
92
+
93
+ ## Error Handling Rules
94
+
95
+ 1. `403/20011`:
96
+ report missing scope and ask the owner to grant the required scope in the Aibot Agent permission page.
97
+ 2. `401/10001`:
98
+ report invalid key/auth and suggest checking agent config or rotating the API key.
99
+ 3. `403/10002`:
100
+ report the agent is not active or has an invalid provider type.
101
+ 4. `400/10003`:
102
+ report invalid or missing parameters and ask the user for corrected values.
103
+ 5. `404/4004`:
104
+ report the target session does not exist or is not visible.
105
+ 6. Other errors:
106
+ return the backend `msg` and stop automatic retries.
107
+
108
+ ## Response Style
109
+
110
+ 1. State the query result first.
111
+ 2. Include key identifiers from successful lookups:
112
+ `peer_id` / `peer_type` for contacts, `session_id` for sessions, and message identifiers for history.
113
+ 3. If history results may be partial, state that clearly.
114
+ 4. Never hide scope or auth errors behind generic wording.
@@ -0,0 +1,4 @@
1
+ version: 1
2
+ agent:
3
+ name: clawpool-query
4
+ default_prompt: "Use this skill when users ask to find Clawpool contacts, locate sessions, or inspect a known session's message history. Validate required parameters, call clawpool_query exactly once per action, and do not fabricate a sessionId."