@clawling/clawchat-plugin-openclaw 2026.8.4-1 → 2026.8.5-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/dist/src/api-client.js +10 -0
- package/dist/src/friend-request-turn.js +83 -0
- package/dist/src/skill-update.js +16 -6
- package/dist/src/tools-schema.js +10 -0
- package/dist/src/tools.js +29 -1
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -1
- package/skills/manifest.json +3 -3
- package/src/api-client.ts +21 -0
- package/src/skill-update.ts +16 -6
- package/src/tools-schema.ts +12 -0
- package/src/tools.ts +34 -0
package/dist/src/api-client.js
CHANGED
|
@@ -398,6 +398,16 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
398
398
|
assertNonBlankId(conversationId, "leaveConversation: conversationId");
|
|
399
399
|
return await call("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/leave`);
|
|
400
400
|
},
|
|
401
|
+
async addConversationMember(conversationId, userId) {
|
|
402
|
+
assertNonBlankId(conversationId, "addConversationMember: conversationId");
|
|
403
|
+
assertNonBlankId(userId, "addConversationMember: userId");
|
|
404
|
+
const cid = conversationId.trim();
|
|
405
|
+
const uid = userId.trim();
|
|
406
|
+
return await call("POST", `/v1/conversations/${encodeURIComponent(cid)}/members`, {
|
|
407
|
+
body: JSON.stringify({ user_id: uid }),
|
|
408
|
+
headers: { "content-type": "application/json" },
|
|
409
|
+
});
|
|
410
|
+
},
|
|
401
411
|
async patchConversation(conversationId, patch) {
|
|
402
412
|
assertNonBlankId(conversationId, "patchConversation: conversationId");
|
|
403
413
|
const body = pickPatch(patch, ["title", "description"], "patchConversation");
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic reasoning-turn builder for `friend.request` notify.signal events.
|
|
3
|
+
*
|
|
4
|
+
* When the server fires a `friend.request` signal the runtime dispatches one
|
|
5
|
+
* deduped synthetic `message.send` envelope so the agent can reason about the
|
|
6
|
+
* pending request. The prompt text varies by the current "friend.add" permission
|
|
7
|
+
* policy state: a deny policy yields a decline/inform prompt; ask or allow
|
|
8
|
+
* yields a prompt that instructs the agent to review the request via the
|
|
9
|
+
* `clawchat_list_friend_requests` tool.
|
|
10
|
+
*/
|
|
11
|
+
import { EVENT } from "./protocol-types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Returns canned prompt text for a friend-request reasoning turn based on the
|
|
14
|
+
* current "friend.add" permission policy state.
|
|
15
|
+
*
|
|
16
|
+
* - `deny` → inform the agent it should decline; no accept instruction.
|
|
17
|
+
* - `ask` / `allow` → instruct the agent to review the pending request.
|
|
18
|
+
*
|
|
19
|
+
* The requester's user id is embedded so the agent does not go looking up the
|
|
20
|
+
* synthetic sender ("clawchat-friend-request" is not a real user).
|
|
21
|
+
*/
|
|
22
|
+
export function friendRequestPromptFor(state, requesterUserId) {
|
|
23
|
+
const arrived = requesterUserId
|
|
24
|
+
? `A new friend request has arrived from user ${requesterUserId}.`
|
|
25
|
+
: "A new friend request has arrived.";
|
|
26
|
+
if (state === "deny") {
|
|
27
|
+
return [
|
|
28
|
+
arrived,
|
|
29
|
+
"Your current friend-add policy is set to deny.",
|
|
30
|
+
"Do not add this contact.",
|
|
31
|
+
"You may inform the requester that you cannot add them at this time.",
|
|
32
|
+
].join(" ");
|
|
33
|
+
}
|
|
34
|
+
return [
|
|
35
|
+
arrived,
|
|
36
|
+
"Please review the pending request by calling `clawchat_list_friend_requests`",
|
|
37
|
+
"and decide whether to accept it.",
|
|
38
|
+
].join(" ");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds a synthetic `message.send` envelope that triggers one agent reasoning
|
|
42
|
+
* turn for a pending friend request. The envelope shape mirrors the
|
|
43
|
+
* activation-bootstrap envelope; it targets the owner's direct conversation so
|
|
44
|
+
* the agent has context about who it is reasoning for.
|
|
45
|
+
*/
|
|
46
|
+
export function buildFriendRequestEnvelope(params) {
|
|
47
|
+
const { account, state, entityId, ownerConversationId } = params;
|
|
48
|
+
const text = friendRequestPromptFor(state, entityId);
|
|
49
|
+
const now = Date.now();
|
|
50
|
+
// Fall back to ownerUserId only when no activation conversation is recorded:
|
|
51
|
+
// the turn still runs (the agent can act via tools, e.g. accept the request),
|
|
52
|
+
// but its in-chat replies will not be deliverable until activation records
|
|
53
|
+
// the owner conversation.
|
|
54
|
+
return {
|
|
55
|
+
version: "2",
|
|
56
|
+
event: EVENT.MESSAGE_SEND,
|
|
57
|
+
trace_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
|
|
58
|
+
emitted_at: now,
|
|
59
|
+
chat_id: ownerConversationId ?? account.ownerUserId,
|
|
60
|
+
chat_type: "direct",
|
|
61
|
+
to: { id: account.userId, type: "direct" },
|
|
62
|
+
sender: {
|
|
63
|
+
id: "clawchat-friend-request",
|
|
64
|
+
type: "direct",
|
|
65
|
+
nick_name: "ClawChat",
|
|
66
|
+
},
|
|
67
|
+
payload: {
|
|
68
|
+
message_id: `clawchat-plugin-openclaw-friend-request-${entityId}-${now}`,
|
|
69
|
+
message_mode: "normal",
|
|
70
|
+
message: {
|
|
71
|
+
body: { fragments: [{ kind: "text", text }] },
|
|
72
|
+
context: { mentions: [], reply: null },
|
|
73
|
+
streaming: {
|
|
74
|
+
status: "static",
|
|
75
|
+
sequence: 0,
|
|
76
|
+
mutation_policy: "sealed",
|
|
77
|
+
started_at: null,
|
|
78
|
+
completed_at: null,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
package/dist/src/skill-update.js
CHANGED
|
@@ -38,9 +38,11 @@ import { fileURLToPath } from "node:url";
|
|
|
38
38
|
* - All network IO goes through an injected `FetchLike`; tests never touch the
|
|
39
39
|
* real network.
|
|
40
40
|
*
|
|
41
|
-
* Cross-language contract / spec: see
|
|
42
|
-
*
|
|
43
|
-
*
|
|
41
|
+
* Cross-language contract / spec: see `docs/clawchat-plugin-openclaw.md`
|
|
42
|
+
* §"Conversational skill hot-update" for this adapter's end of the flow,
|
|
43
|
+
* `docs/client-integration.md` for the `clawchat.skill.update.check` signal
|
|
44
|
+
* shape, and the install-cli repo's `skills/README.md` for the canonical skill
|
|
45
|
+
* source and `manifest.json` contract.
|
|
44
46
|
*/
|
|
45
47
|
// ---------------------------------------------------------------------------
|
|
46
48
|
// Constants — fixed contract (must match the install-cli `config.ts`).
|
|
@@ -53,10 +55,18 @@ import { fileURLToPath } from "node:url";
|
|
|
53
55
|
*/
|
|
54
56
|
export const OFFICIAL_SKILLS_BASE = "https://raw.githubusercontent.com/clawling/clawchat-plugin-install-cli";
|
|
55
57
|
/**
|
|
56
|
-
* Default git ref for the skills tree
|
|
57
|
-
*
|
|
58
|
+
* Default git ref for the skills tree — an immutable `skills-vX.Y.Z` tag, not
|
|
59
|
+
* the moving `main`. Nothing supplies a target version today (the trigger
|
|
60
|
+
* signal is content-free), so this constant is the ref every fetch uses: on
|
|
61
|
+
* `main` a released plugin would follow whatever landed in the skills tree
|
|
62
|
+
* since, and convergence compares raw bytes, so an in-progress edit is enough
|
|
63
|
+
* to prompt the owner for an "update".
|
|
64
|
+
*
|
|
65
|
+
* Moving the pin is a deliberate release: publish the new `skills-vX.Y.Z` tag
|
|
66
|
+
* in the install-cli repo, bump this constant, ship it. `liveware-sample.ts`
|
|
67
|
+
* imports the same ref, so the `livewares` tree at that tag is pinned too.
|
|
58
68
|
*/
|
|
59
|
-
export const DEFAULT_SKILLS_REF = "
|
|
69
|
+
export const DEFAULT_SKILLS_REF = "skills-v1.6.0";
|
|
60
70
|
/** Refuse to treat an absurdly large response as a skill file (defence in depth). */
|
|
61
71
|
export const MAX_SKILL_BYTES = 256 * 1024;
|
|
62
72
|
/** This adapter's host target inside `skills/manifest.json`. */
|
package/dist/src/tools-schema.js
CHANGED
|
@@ -128,6 +128,16 @@ export const ClawchatLeaveGroupSchema = Type.Object({
|
|
|
128
128
|
description: "Concrete ClawChat group conversation id to leave",
|
|
129
129
|
}),
|
|
130
130
|
});
|
|
131
|
+
export const ClawchatAddGroupMemberSchema = Type.Object({
|
|
132
|
+
conversationId: Type.String({
|
|
133
|
+
minLength: 1,
|
|
134
|
+
description: "Concrete ClawChat group conversation id to add the user to",
|
|
135
|
+
}),
|
|
136
|
+
userId: Type.String({
|
|
137
|
+
minLength: 1,
|
|
138
|
+
description: "Concrete ClawChat user id (usr_...) to add to the group",
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
131
141
|
export const ClawchatMentionMessageSchema = Type.Object({
|
|
132
142
|
chatId: Type.String({
|
|
133
143
|
minLength: 1,
|
package/dist/src/tools.js
CHANGED
|
@@ -12,7 +12,7 @@ import { getOpenclawClawlingClient, } from "./runtime.js";
|
|
|
12
12
|
import { markTerminalClawChatSend, getCurrentTerminalSendScope } from "./terminal-send.js";
|
|
13
13
|
import { editClawChatMemoryBody, readClawChatMemoryFile, resolveClawChatMemoryPath, searchClawChatMemory, writeClawChatMemoryBody, } from "./clawchat-memory.js";
|
|
14
14
|
import { pullGroupMetadata, pullOwnerMetadata, pullUserMetadata, pushMetadata, updateMetadata, } from "./clawchat-metadata.js";
|
|
15
|
-
import { ClawchatGetAccountProfileSchema, ClawchatGetConversationSchema, ClawchatGetMomentSchema, ClawchatGetUserProfileSchema, ClawchatLeaveGroupSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, ClawchatReactMessageSchema, ClawchatReplyMomentCommentSchema, ClawchatRejectFriendRequestSchema, ClawchatRemoveFriendSchema, ClawchatSearchUsersSchema, ClawchatSendFriendRequestSchema, ClawchatToggleMomentReactionSchema, ClawchatUpdateAccountProfileSchema, ClawchatUploadAvatarImageSchema, ClawchatRegisterAppSchema, ClawchatListAppsSchema, ClawchatUnregisterAppSchema, ClawchatLivewareLoginSchema, } from "./tools-schema.js";
|
|
15
|
+
import { ClawchatGetAccountProfileSchema, ClawchatGetConversationSchema, ClawchatGetMomentSchema, ClawchatGetUserProfileSchema, ClawchatLeaveGroupSchema, ClawchatAddGroupMemberSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, ClawchatReactMessageSchema, ClawchatReplyMomentCommentSchema, ClawchatRejectFriendRequestSchema, ClawchatRemoveFriendSchema, ClawchatSearchUsersSchema, ClawchatSendFriendRequestSchema, ClawchatToggleMomentReactionSchema, ClawchatUpdateAccountProfileSchema, ClawchatUploadAvatarImageSchema, ClawchatRegisterAppSchema, ClawchatListAppsSchema, ClawchatUnregisterAppSchema, ClawchatLivewareLoginSchema, } from "./tools-schema.js";
|
|
16
16
|
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
|
|
17
17
|
// Owner-approval gate business codes (must match the ClawChat backend's owner-approval codes).
|
|
18
18
|
const CODE_PENDING_APPROVAL = 21001;
|
|
@@ -808,6 +808,34 @@ export function registerOpenclawClawlingTools(api, options = {}) {
|
|
|
808
808
|
});
|
|
809
809
|
},
|
|
810
810
|
}, { name: "clawchat_leave_group" });
|
|
811
|
+
api.registerTool({
|
|
812
|
+
name: "clawchat_add_group_member",
|
|
813
|
+
label: "Add ClawChat Group Member",
|
|
814
|
+
description: toolDescription("Add a specified ClawChat user to a group conversation the agent is a member of. " +
|
|
815
|
+
"TRIGGER - invoke only when the user explicitly asks the agent to add, invite, or pull a specific person into a specific ClawChat group, and both a concrete conversationId and a concrete userId are available. " +
|
|
816
|
+
"Never guess a userId from a name or nickname — use ids from ClawChat Group Message Metadata, clawchat_list_account_friends, or clawchat_search_users. " +
|
|
817
|
+
"Groups only: direct conversations are rejected by the server. " +
|
|
818
|
+
"The target must already be the agent's ClawChat friend, and the agent needs the group-management permission granted by its owner; if the call fails for either reason, explain that to the user and do not retry."),
|
|
819
|
+
parameters: ClawchatAddGroupMemberSchema,
|
|
820
|
+
async execute(_callId, params) {
|
|
821
|
+
return await recordClawchatToolCall("clawchat_add_group_member", params, async () => {
|
|
822
|
+
const p = params;
|
|
823
|
+
const built = buildClient();
|
|
824
|
+
if (!built.ok)
|
|
825
|
+
return built.error;
|
|
826
|
+
try {
|
|
827
|
+
const data = await built.client.addConversationMember(p.conversationId, p.userId);
|
|
828
|
+
return jsonResponse(data);
|
|
829
|
+
}
|
|
830
|
+
catch (err) {
|
|
831
|
+
if (err instanceof ClawlingApiError) {
|
|
832
|
+
return apiError(err);
|
|
833
|
+
}
|
|
834
|
+
return genericError(err);
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
},
|
|
838
|
+
}, { name: "clawchat_add_group_member" });
|
|
811
839
|
api.registerTool({
|
|
812
840
|
name: "clawchat_mention_message",
|
|
813
841
|
label: "Send ClawChat Mention Message",
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/skills/manifest.json
CHANGED
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
},
|
|
30
30
|
"hermes": {
|
|
31
31
|
"clawchat-core": {
|
|
32
|
-
"version": "1.
|
|
32
|
+
"version": "1.7.0",
|
|
33
33
|
"path": "hermes/clawchat-core/SKILL.md",
|
|
34
|
-
"sha256": "
|
|
35
|
-
"bytes":
|
|
34
|
+
"sha256": "ea5118a99ddad7c9ce9c1437a4e33fbd76f45572998bb1722a70f4aa5e0e76aa",
|
|
35
|
+
"bytes": 17557
|
|
36
36
|
},
|
|
37
37
|
"clawchat-liveware": {
|
|
38
38
|
"version": "1.1.0",
|
package/src/api-client.ts
CHANGED
|
@@ -135,6 +135,10 @@ export interface OpenclawClawlingApiClient {
|
|
|
135
135
|
deleteMomentComment(params: { momentId: number; commentId: number }): Promise<{ ok: boolean }>;
|
|
136
136
|
getConversation(conversationId: string): Promise<{ conversation: ConversationDetails }>;
|
|
137
137
|
leaveConversation(conversationId: string): Promise<{ ok: boolean }>;
|
|
138
|
+
addConversationMember(
|
|
139
|
+
conversationId: string,
|
|
140
|
+
userId: string,
|
|
141
|
+
): Promise<{ conversation: ConversationDetails }>;
|
|
138
142
|
patchConversation(
|
|
139
143
|
conversationId: string,
|
|
140
144
|
patch: ConversationMetadataPatch,
|
|
@@ -643,6 +647,23 @@ export function createOpenclawClawlingApiClient(opts: ApiClientOptions): Opencla
|
|
|
643
647
|
`/v1/conversations/${encodeURIComponent(conversationId)}/leave`,
|
|
644
648
|
);
|
|
645
649
|
},
|
|
650
|
+
async addConversationMember(
|
|
651
|
+
conversationId,
|
|
652
|
+
userId,
|
|
653
|
+
): Promise<{ conversation: ConversationDetails }> {
|
|
654
|
+
assertNonBlankId(conversationId, "addConversationMember: conversationId");
|
|
655
|
+
assertNonBlankId(userId, "addConversationMember: userId");
|
|
656
|
+
const cid = conversationId.trim();
|
|
657
|
+
const uid = userId.trim();
|
|
658
|
+
return await call<{ conversation: ConversationDetails }>(
|
|
659
|
+
"POST",
|
|
660
|
+
`/v1/conversations/${encodeURIComponent(cid)}/members`,
|
|
661
|
+
{
|
|
662
|
+
body: JSON.stringify({ user_id: uid }),
|
|
663
|
+
headers: { "content-type": "application/json" },
|
|
664
|
+
},
|
|
665
|
+
);
|
|
666
|
+
},
|
|
646
667
|
async patchConversation(
|
|
647
668
|
conversationId: string,
|
|
648
669
|
patch: ConversationMetadataPatch,
|
package/src/skill-update.ts
CHANGED
|
@@ -39,9 +39,11 @@ import { fileURLToPath } from "node:url";
|
|
|
39
39
|
* - All network IO goes through an injected `FetchLike`; tests never touch the
|
|
40
40
|
* real network.
|
|
41
41
|
*
|
|
42
|
-
* Cross-language contract / spec: see
|
|
43
|
-
*
|
|
44
|
-
*
|
|
42
|
+
* Cross-language contract / spec: see `docs/clawchat-plugin-openclaw.md`
|
|
43
|
+
* §"Conversational skill hot-update" for this adapter's end of the flow,
|
|
44
|
+
* `docs/client-integration.md` for the `clawchat.skill.update.check` signal
|
|
45
|
+
* shape, and the install-cli repo's `skills/README.md` for the canonical skill
|
|
46
|
+
* source and `manifest.json` contract.
|
|
45
47
|
*/
|
|
46
48
|
|
|
47
49
|
// ---------------------------------------------------------------------------
|
|
@@ -58,10 +60,18 @@ export const OFFICIAL_SKILLS_BASE =
|
|
|
58
60
|
"https://raw.githubusercontent.com/clawling/clawchat-plugin-install-cli";
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
|
-
* Default git ref for the skills tree
|
|
62
|
-
*
|
|
63
|
+
* Default git ref for the skills tree — an immutable `skills-vX.Y.Z` tag, not
|
|
64
|
+
* the moving `main`. Nothing supplies a target version today (the trigger
|
|
65
|
+
* signal is content-free), so this constant is the ref every fetch uses: on
|
|
66
|
+
* `main` a released plugin would follow whatever landed in the skills tree
|
|
67
|
+
* since, and convergence compares raw bytes, so an in-progress edit is enough
|
|
68
|
+
* to prompt the owner for an "update".
|
|
69
|
+
*
|
|
70
|
+
* Moving the pin is a deliberate release: publish the new `skills-vX.Y.Z` tag
|
|
71
|
+
* in the install-cli repo, bump this constant, ship it. `liveware-sample.ts`
|
|
72
|
+
* imports the same ref, so the `livewares` tree at that tag is pinned too.
|
|
63
73
|
*/
|
|
64
|
-
export const DEFAULT_SKILLS_REF = "
|
|
74
|
+
export const DEFAULT_SKILLS_REF = "skills-v1.6.0";
|
|
65
75
|
|
|
66
76
|
/** Refuse to treat an absurdly large response as a skill file (defence in depth). */
|
|
67
77
|
export const MAX_SKILL_BYTES = 256 * 1024;
|
package/src/tools-schema.ts
CHANGED
|
@@ -208,6 +208,18 @@ export const ClawchatLeaveGroupSchema = Type.Object({
|
|
|
208
208
|
});
|
|
209
209
|
export type ClawchatLeaveGroupParams = Static<typeof ClawchatLeaveGroupSchema>;
|
|
210
210
|
|
|
211
|
+
export const ClawchatAddGroupMemberSchema = Type.Object({
|
|
212
|
+
conversationId: Type.String({
|
|
213
|
+
minLength: 1,
|
|
214
|
+
description: "Concrete ClawChat group conversation id to add the user to",
|
|
215
|
+
}),
|
|
216
|
+
userId: Type.String({
|
|
217
|
+
minLength: 1,
|
|
218
|
+
description: "Concrete ClawChat user id (usr_...) to add to the group",
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
export type ClawchatAddGroupMemberParams = Static<typeof ClawchatAddGroupMemberSchema>;
|
|
222
|
+
|
|
211
223
|
export const ClawchatMentionMessageSchema = Type.Object({
|
|
212
224
|
chatId: Type.String({
|
|
213
225
|
minLength: 1,
|
package/src/tools.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
ClawchatGetMomentSchema,
|
|
44
44
|
ClawchatGetUserProfileSchema,
|
|
45
45
|
ClawchatLeaveGroupSchema,
|
|
46
|
+
ClawchatAddGroupMemberSchema,
|
|
46
47
|
ClawchatAcceptFriendRequestSchema,
|
|
47
48
|
ClawchatMemoryEditSchema,
|
|
48
49
|
ClawchatMemoryReadSchema,
|
|
@@ -86,6 +87,7 @@ import {
|
|
|
86
87
|
type ClawchatGetMomentParams,
|
|
87
88
|
type ClawchatGetUserProfileParams,
|
|
88
89
|
type ClawchatLeaveGroupParams,
|
|
90
|
+
type ClawchatAddGroupMemberParams,
|
|
89
91
|
type ClawchatListFriendRequestsParams,
|
|
90
92
|
type ClawchatListMomentsParams,
|
|
91
93
|
type ClawchatMentionMessageParams,
|
|
@@ -1048,6 +1050,38 @@ export function registerOpenclawClawlingTools(
|
|
|
1048
1050
|
{ name: "clawchat_leave_group" },
|
|
1049
1051
|
);
|
|
1050
1052
|
|
|
1053
|
+
api.registerTool(
|
|
1054
|
+
{
|
|
1055
|
+
name: "clawchat_add_group_member",
|
|
1056
|
+
label: "Add ClawChat Group Member",
|
|
1057
|
+
description: toolDescription(
|
|
1058
|
+
"Add a specified ClawChat user to a group conversation the agent is a member of. " +
|
|
1059
|
+
"TRIGGER - invoke only when the user explicitly asks the agent to add, invite, or pull a specific person into a specific ClawChat group, and both a concrete conversationId and a concrete userId are available. " +
|
|
1060
|
+
"Never guess a userId from a name or nickname — use ids from ClawChat Group Message Metadata, clawchat_list_account_friends, or clawchat_search_users. " +
|
|
1061
|
+
"Groups only: direct conversations are rejected by the server. " +
|
|
1062
|
+
"The target must already be the agent's ClawChat friend, and the agent needs the group-management permission granted by its owner; if the call fails for either reason, explain that to the user and do not retry.",
|
|
1063
|
+
),
|
|
1064
|
+
parameters: ClawchatAddGroupMemberSchema,
|
|
1065
|
+
async execute(_callId, params) {
|
|
1066
|
+
return await recordClawchatToolCall("clawchat_add_group_member", params, async () => {
|
|
1067
|
+
const p = params as ClawchatAddGroupMemberParams;
|
|
1068
|
+
const built = buildClient();
|
|
1069
|
+
if (!built.ok) return built.error;
|
|
1070
|
+
try {
|
|
1071
|
+
const data = await built.client.addConversationMember(p.conversationId, p.userId);
|
|
1072
|
+
return jsonResponse(data);
|
|
1073
|
+
} catch (err) {
|
|
1074
|
+
if (err instanceof ClawlingApiError) {
|
|
1075
|
+
return apiError(err);
|
|
1076
|
+
}
|
|
1077
|
+
return genericError(err);
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
},
|
|
1081
|
+
},
|
|
1082
|
+
{ name: "clawchat_add_group_member" },
|
|
1083
|
+
);
|
|
1084
|
+
|
|
1051
1085
|
api.registerTool(
|
|
1052
1086
|
{
|
|
1053
1087
|
name: "clawchat_mention_message",
|