@clawling/clawchat-plugin-openclaw 2026.7.20-1 → 2026.7.23-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 +4 -0
- package/dist/src/liveware-cli.js +19 -7
- package/dist/src/tools-schema.js +5 -0
- package/dist/src/tools.js +29 -1
- package/openclaw.plugin.json +1 -0
- package/package.json +1 -1
- package/skills/clawchat-core/SKILL.md +12 -2
- package/skills/clawchat-liveware/SKILL.md +24 -3
- package/skills/manifest.json +12 -12
- package/src/api-client.ts +8 -0
- package/src/liveware-cli.ts +19 -6
- package/src/tools-schema.ts +7 -0
- package/src/tools.ts +34 -0
package/dist/src/api-client.js
CHANGED
|
@@ -391,6 +391,10 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
391
391
|
async getConversation(conversationId) {
|
|
392
392
|
return await call("GET", `/v1/conversations/${encodeURIComponent(conversationId)}`);
|
|
393
393
|
},
|
|
394
|
+
async leaveConversation(conversationId) {
|
|
395
|
+
assertNonBlankId(conversationId, "leaveConversation: conversationId");
|
|
396
|
+
return await call("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/leave`);
|
|
397
|
+
},
|
|
394
398
|
async patchConversation(conversationId, patch) {
|
|
395
399
|
assertNonBlankId(conversationId, "patchConversation: conversationId");
|
|
396
400
|
const body = pickPatch(patch, ["title", "description"], "patchConversation");
|
package/dist/src/liveware-cli.js
CHANGED
|
@@ -10,12 +10,22 @@ export function livewareDir(stateDir) {
|
|
|
10
10
|
const root = stateDir ?? resolveStateDir();
|
|
11
11
|
return path.join(root, "clawchat", "liveware");
|
|
12
12
|
}
|
|
13
|
+
/** Local filename for the downloaded binary; Windows needs a .exe suffix. */
|
|
14
|
+
export function livewareBinaryName(plat = process.platform) {
|
|
15
|
+
return plat === "win32" ? "liveware.exe" : "liveware";
|
|
16
|
+
}
|
|
13
17
|
/** Map host platform/arch to the liveware asset filename, or null if unsupported. */
|
|
14
18
|
export function platformAssets(plat = process.platform, arch = process.arch) {
|
|
15
|
-
const os = plat === "darwin" ? "darwin" : plat === "linux" ? "linux" : null;
|
|
19
|
+
const os = plat === "darwin" ? "darwin" : plat === "linux" ? "linux" : plat === "win32" ? "windows" : null;
|
|
16
20
|
const cpu = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
|
|
17
21
|
if (!os || !cpu)
|
|
18
22
|
return null;
|
|
23
|
+
// Windows only ships an amd64 build, published with a .exe suffix.
|
|
24
|
+
if (os === "windows") {
|
|
25
|
+
if (cpu !== "amd64")
|
|
26
|
+
return null;
|
|
27
|
+
return { liveware: "liveware-windows-amd64.exe" };
|
|
28
|
+
}
|
|
19
29
|
return { liveware: `liveware-${os}-${cpu}` };
|
|
20
30
|
}
|
|
21
31
|
function findOnPath(name) {
|
|
@@ -41,9 +51,10 @@ function findOnPath(name) {
|
|
|
41
51
|
* 3. otherwise → null
|
|
42
52
|
*/
|
|
43
53
|
export function resolveLivewarePath(stateDir) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
const name = livewareBinaryName();
|
|
55
|
+
if (findOnPath(name))
|
|
56
|
+
return name;
|
|
57
|
+
const local = path.join(livewareDir(stateDir), name);
|
|
47
58
|
try {
|
|
48
59
|
fs.accessSync(local, fs.constants.X_OK);
|
|
49
60
|
return local;
|
|
@@ -71,10 +82,11 @@ async function downloadTo(url, dest) {
|
|
|
71
82
|
export async function ensureLivewareCli(opts = {}) {
|
|
72
83
|
const { stateDir, log } = opts;
|
|
73
84
|
try {
|
|
74
|
-
|
|
85
|
+
const name = livewareBinaryName();
|
|
86
|
+
if (findOnPath(name))
|
|
75
87
|
return; // PATH wins
|
|
76
88
|
const dir = livewareDir(stateDir);
|
|
77
|
-
const target = path.join(dir,
|
|
89
|
+
const target = path.join(dir, name);
|
|
78
90
|
if (fs.existsSync(target))
|
|
79
91
|
return;
|
|
80
92
|
const assets = platformAssets();
|
|
@@ -83,7 +95,7 @@ export async function ensureLivewareCli(opts = {}) {
|
|
|
83
95
|
return;
|
|
84
96
|
}
|
|
85
97
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
86
|
-
await downloadTo(LIVEWARE_BASE_URL + assets.liveware, path.join(dir,
|
|
98
|
+
await downloadTo(LIVEWARE_BASE_URL + assets.liveware, path.join(dir, name));
|
|
87
99
|
log?.debug?.(`clawchat-plugin-openclaw: liveware CLI downloaded to ${dir}`);
|
|
88
100
|
}
|
|
89
101
|
catch (err) {
|
package/dist/src/tools-schema.js
CHANGED
|
@@ -123,6 +123,11 @@ export const ClawchatGetConversationSchema = Type.Object({
|
|
|
123
123
|
description: "Concrete ClawChat conversation id to fetch",
|
|
124
124
|
}),
|
|
125
125
|
});
|
|
126
|
+
export const ClawchatLeaveGroupSchema = Type.Object({
|
|
127
|
+
conversationId: Type.String({
|
|
128
|
+
description: "Concrete ClawChat group conversation id to leave",
|
|
129
|
+
}),
|
|
130
|
+
});
|
|
126
131
|
export const ClawchatMentionMessageSchema = Type.Object({
|
|
127
132
|
chatId: Type.String({
|
|
128
133
|
minLength: 1,
|
package/dist/src/tools.js
CHANGED
|
@@ -12,7 +12,7 @@ import { getOpenclawClawlingClient, } from "./runtime.js";
|
|
|
12
12
|
import { markTerminalClawChatSend } 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, ClawchatGetUserProfileSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, ClawchatReplyMomentCommentSchema, ClawchatRejectFriendRequestSchema, ClawchatRemoveFriendSchema, ClawchatSearchUsersSchema, ClawchatSendFriendRequestSchema, ClawchatToggleMomentReactionSchema, ClawchatUpdateAccountProfileSchema, ClawchatUploadAvatarImageSchema, ClawchatRegisterAppSchema, ClawchatListAppsSchema, ClawchatUnregisterAppSchema, ClawchatLivewareLoginSchema, } from "./tools-schema.js";
|
|
15
|
+
import { ClawchatGetAccountProfileSchema, ClawchatGetConversationSchema, ClawchatGetUserProfileSchema, ClawchatLeaveGroupSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, 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;
|
|
@@ -780,6 +780,34 @@ export function registerOpenclawClawlingTools(api, options = {}) {
|
|
|
780
780
|
});
|
|
781
781
|
},
|
|
782
782
|
}, { name: "clawchat_get_conversation" });
|
|
783
|
+
api.registerTool({
|
|
784
|
+
name: "clawchat_leave_group",
|
|
785
|
+
label: "Leave ClawChat Group",
|
|
786
|
+
description: toolDescription("Leave a ClawChat group conversation the agent is currently a member of. " +
|
|
787
|
+
"TRIGGER - invoke only when the user explicitly asks the agent to leave, exit, or quit a specific ClawChat group and provides a concrete conversationId. " +
|
|
788
|
+
"Groups only: direct conversations are rejected by the server. " +
|
|
789
|
+
"If the agent is the group owner, leaving auto-transfers ownership to the earliest human member; if no human member remains, the group is dissolved. " +
|
|
790
|
+
"After this tool succeeds, output only <clawchat:no-reply/> and do not send a normal follow-up reply."),
|
|
791
|
+
parameters: ClawchatLeaveGroupSchema,
|
|
792
|
+
async execute(_callId, params) {
|
|
793
|
+
return await recordClawchatToolCall("clawchat_leave_group", params, async () => {
|
|
794
|
+
const p = params;
|
|
795
|
+
const built = buildClient();
|
|
796
|
+
if (!built.ok)
|
|
797
|
+
return built.error;
|
|
798
|
+
try {
|
|
799
|
+
const data = await built.client.leaveConversation(p.conversationId);
|
|
800
|
+
return jsonResponse(data);
|
|
801
|
+
}
|
|
802
|
+
catch (err) {
|
|
803
|
+
if (err instanceof ClawlingApiError) {
|
|
804
|
+
return apiError(err);
|
|
805
|
+
}
|
|
806
|
+
return genericError(err);
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
},
|
|
810
|
+
}, { name: "clawchat_leave_group" });
|
|
783
811
|
api.registerTool({
|
|
784
812
|
name: "clawchat_mention_message",
|
|
785
813
|
label: "Send ClawChat Mention Message",
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clawchat-core
|
|
3
|
-
version: 1.
|
|
4
|
-
description: Use when a request involves ClawChat profile, friends, user search, moments/dynamics, comments, reactions, avatar, media, memory, output visibility, read-only conversation lookup, or plugin install/update/activation.
|
|
3
|
+
version: 1.1.0
|
|
4
|
+
description: Use when a request involves ClawChat profile, friends, user search, moments/dynamics, comments, reactions, avatar, media, memory, output visibility, read-only conversation lookup, sending an image, file, or voice/audio clip into a conversation, or plugin install/update/activation.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ClawChat
|
|
@@ -16,6 +16,16 @@ This skill guides agent behavior for ClawChat-aware tasks. Use the registered Cl
|
|
|
16
16
|
- If a requested ClawChat tool is unavailable or returns a config error, report that result and stop instead of bypassing the plugin.
|
|
17
17
|
- Use the `/clawchat-output` slash command when the user asks to change how much ClawChat runtime output is shown in the current conversation.
|
|
18
18
|
|
|
19
|
+
## Sending an Image, File, or Voice Message
|
|
20
|
+
|
|
21
|
+
To deliver an image, file, or voice/audio clip into the current ClawChat conversation, use the OpenClaw **message tool** with `action='send'` and `media` set to a local file path or an HTTPS URL. This is a host message-tool capability, not a `clawchat_*` tool — the `clawchat_upload_avatar_image` / moment-image tools are a separate avatar/moments surface and do not post into a conversation.
|
|
22
|
+
|
|
23
|
+
- ClawChat detects the media type from the file and renders it: images inline, audio files (`.mp3`, `.m4a`, `.wav`, `.ogg`, `.aac`, …) as **playable voice messages**, everything else as a downloadable file. There is no separate voice tool or `voice` kind — a voice message is just audio media, so sending a genuine audio file is how you "send a voice message".
|
|
24
|
+
- Use a real audio file with its normal extension so its type is recognized as audio; an extension-less or mislabeled file may arrive as a plain file. The clip length is shown on the recipient side automatically — you do not set a duration.
|
|
25
|
+
- Send several assets by passing multiple URLs; any accompanying reply text becomes the caption. For web images, pass a suitable HTTPS URL directly as `media` — do not download it first.
|
|
26
|
+
- Omit `target` to reply to the current chat. For another chat use `target="cc:{chat_id}"` (direct) or `target="cc:group:{chat_id}"` (group).
|
|
27
|
+
- Do not paste a file's contents into the message or claim you cannot send attachments as a substitute; attach it this way and report any delivery failure.
|
|
28
|
+
|
|
19
29
|
## OpenClaw CLI
|
|
20
30
|
|
|
21
31
|
Use CLI commands only for installing, updating, activating, or refreshing the OpenClaw ClawChat plugin. Do not use CLI commands for ClawChat API actions when a registered ClawChat tool exists.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clawchat-liveware
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.1.0
|
|
4
4
|
description: Use when the user wants to expose this agent's local web service to the public internet via the liveware CLI and make it appear as an app in their ClawChat chat with this agent. Covers logging in to liveware with the ClawChat account, creating a liveware app, binding a tunnel to a local port, and registering the public URL to ClawChat.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -55,9 +55,30 @@ ClawChat so it shows as an app tile in the owner's chat with this agent.
|
|
|
55
55
|
- To remove one: `clawchat_unregister_app(appId="<app id>")` (this only removes it from
|
|
56
56
|
ClawChat; tear down the liveware tunnel/app with liveware's own commands separately).
|
|
57
57
|
|
|
58
|
+
## Identifying the viewing user (server-side)
|
|
59
|
+
|
|
60
|
+
When a ClawChat user opens the liveware, the ClawChat liveware tunnel authenticates the
|
|
61
|
+
request and forwards the viewer's ClawChat `user_id` to your web service as a request header.
|
|
62
|
+
On the **server side** of your web service, read the `user_id` from either header (both carry
|
|
63
|
+
the same value):
|
|
64
|
+
|
|
65
|
+
- `X-User-Id`
|
|
66
|
+
- `X-Clawchat-User-Id`
|
|
67
|
+
|
|
68
|
+
Caveats:
|
|
69
|
+
|
|
70
|
+
- This is **server-side only** — read the incoming request headers in your web service. Do
|
|
71
|
+
NOT try to obtain the viewer's identity from client-side page JavaScript.
|
|
72
|
+
- The headers are injected by the ClawChat liveware tunnel, so they are present only for
|
|
73
|
+
requests that arrive through it. A page opened directly in an ordinary browser (outside
|
|
74
|
+
ClawChat) carries neither header — treat the user as anonymous when both are absent, and
|
|
75
|
+
never trust a client-supplied value for these header names.
|
|
76
|
+
|
|
58
77
|
## Notes
|
|
59
78
|
|
|
60
79
|
- Apps can be created up to liveware's account limit; surface its error rather than working
|
|
61
80
|
around it.
|
|
62
|
-
- The registered web app
|
|
63
|
-
|
|
81
|
+
- The registered web app runs inside a sandboxed container (mobile in-app webview / desktop
|
|
82
|
+
container window). Page JavaScript cannot read the viewer's ClawChat identity — the
|
|
83
|
+
viewer's `user_id` arrives as the `X-User-Id` / `X-Clawchat-User-Id` request header,
|
|
84
|
+
readable server-side only (see "Identifying the viewing user").
|
package/skills/manifest.json
CHANGED
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
"skills": {
|
|
4
4
|
"openclaw": {
|
|
5
5
|
"clawchat-core": {
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.1.0",
|
|
7
7
|
"path": "openclaw/clawchat-core/SKILL.md",
|
|
8
|
-
"sha256": "
|
|
9
|
-
"bytes":
|
|
8
|
+
"sha256": "f5a25e584ddf62c2a6880a85a7bd93765d05809f7612791b73600ca830445116",
|
|
9
|
+
"bytes": 8909
|
|
10
10
|
},
|
|
11
11
|
"clawchat-liveware": {
|
|
12
|
-
"version": "1.
|
|
12
|
+
"version": "1.1.0",
|
|
13
13
|
"path": "shared/clawchat-liveware/SKILL.md",
|
|
14
|
-
"sha256": "
|
|
15
|
-
"bytes":
|
|
14
|
+
"sha256": "c59a8156f8283f9f2a71231813322ce2162a50c5f0c9ad3d828be43eb9ae967a",
|
|
15
|
+
"bytes": 4634
|
|
16
16
|
},
|
|
17
17
|
"clawchat-set-greeting": {
|
|
18
18
|
"version": "1.0.0",
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
},
|
|
30
30
|
"hermes": {
|
|
31
31
|
"clawchat-core": {
|
|
32
|
-
"version": "1.
|
|
32
|
+
"version": "1.2.0",
|
|
33
33
|
"path": "hermes/clawchat-core/SKILL.md",
|
|
34
|
-
"sha256": "
|
|
35
|
-
"bytes":
|
|
34
|
+
"sha256": "4a73379ff38f089b3120160f09a7eb1b7c617ec0bd23b9c905fb4b2184d6e239",
|
|
35
|
+
"bytes": 11106
|
|
36
36
|
},
|
|
37
37
|
"clawchat-liveware": {
|
|
38
|
-
"version": "1.
|
|
38
|
+
"version": "1.1.0",
|
|
39
39
|
"path": "shared/clawchat-liveware/SKILL.md",
|
|
40
|
-
"sha256": "
|
|
41
|
-
"bytes":
|
|
40
|
+
"sha256": "c59a8156f8283f9f2a71231813322ce2162a50c5f0c9ad3d828be43eb9ae967a",
|
|
41
|
+
"bytes": 4634
|
|
42
42
|
},
|
|
43
43
|
"clawchat-set-greeting": {
|
|
44
44
|
"version": "1.0.0",
|
package/src/api-client.ts
CHANGED
|
@@ -133,6 +133,7 @@ export interface OpenclawClawlingApiClient {
|
|
|
133
133
|
}): Promise<{ comment: MomentComment }>;
|
|
134
134
|
deleteMomentComment(params: { momentId: number; commentId: number }): Promise<{ ok: boolean }>;
|
|
135
135
|
getConversation(conversationId: string): Promise<{ conversation: ConversationDetails }>;
|
|
136
|
+
leaveConversation(conversationId: string): Promise<{ ok: boolean }>;
|
|
136
137
|
patchConversation(
|
|
137
138
|
conversationId: string,
|
|
138
139
|
patch: ConversationMetadataPatch,
|
|
@@ -631,6 +632,13 @@ export function createOpenclawClawlingApiClient(opts: ApiClientOptions): Opencla
|
|
|
631
632
|
`/v1/conversations/${encodeURIComponent(conversationId)}`,
|
|
632
633
|
);
|
|
633
634
|
},
|
|
635
|
+
async leaveConversation(conversationId): Promise<{ ok: boolean }> {
|
|
636
|
+
assertNonBlankId(conversationId, "leaveConversation: conversationId");
|
|
637
|
+
return await call<{ ok: boolean }>(
|
|
638
|
+
"POST",
|
|
639
|
+
`/v1/conversations/${encodeURIComponent(conversationId)}/leave`,
|
|
640
|
+
);
|
|
641
|
+
},
|
|
634
642
|
async patchConversation(
|
|
635
643
|
conversationId: string,
|
|
636
644
|
patch: ConversationMetadataPatch,
|
package/src/liveware-cli.ts
CHANGED
|
@@ -20,14 +20,25 @@ export function livewareDir(stateDir?: string): string {
|
|
|
20
20
|
return path.join(root, "clawchat", "liveware");
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** Local filename for the downloaded binary; Windows needs a .exe suffix. */
|
|
24
|
+
export function livewareBinaryName(plat: string = process.platform): string {
|
|
25
|
+
return plat === "win32" ? "liveware.exe" : "liveware";
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
/** Map host platform/arch to the liveware asset filename, or null if unsupported. */
|
|
24
29
|
export function platformAssets(
|
|
25
30
|
plat: string = process.platform,
|
|
26
31
|
arch: string = process.arch,
|
|
27
32
|
): { liveware: string } | null {
|
|
28
|
-
const os =
|
|
33
|
+
const os =
|
|
34
|
+
plat === "darwin" ? "darwin" : plat === "linux" ? "linux" : plat === "win32" ? "windows" : null;
|
|
29
35
|
const cpu = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
|
|
30
36
|
if (!os || !cpu) return null;
|
|
37
|
+
// Windows only ships an amd64 build, published with a .exe suffix.
|
|
38
|
+
if (os === "windows") {
|
|
39
|
+
if (cpu !== "amd64") return null;
|
|
40
|
+
return { liveware: "liveware-windows-amd64.exe" };
|
|
41
|
+
}
|
|
31
42
|
return { liveware: `liveware-${os}-${cpu}` };
|
|
32
43
|
}
|
|
33
44
|
|
|
@@ -53,8 +64,9 @@ function findOnPath(name: string): string | null {
|
|
|
53
64
|
* 3. otherwise → null
|
|
54
65
|
*/
|
|
55
66
|
export function resolveLivewarePath(stateDir?: string): string | null {
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
const name = livewareBinaryName();
|
|
68
|
+
if (findOnPath(name)) return name;
|
|
69
|
+
const local = path.join(livewareDir(stateDir), name);
|
|
58
70
|
try {
|
|
59
71
|
fs.accessSync(local, fs.constants.X_OK);
|
|
60
72
|
return local;
|
|
@@ -83,9 +95,10 @@ export async function ensureLivewareCli(
|
|
|
83
95
|
): Promise<void> {
|
|
84
96
|
const { stateDir, log } = opts;
|
|
85
97
|
try {
|
|
86
|
-
|
|
98
|
+
const name = livewareBinaryName();
|
|
99
|
+
if (findOnPath(name)) return; // PATH wins
|
|
87
100
|
const dir = livewareDir(stateDir);
|
|
88
|
-
const target = path.join(dir,
|
|
101
|
+
const target = path.join(dir, name);
|
|
89
102
|
if (fs.existsSync(target)) return;
|
|
90
103
|
|
|
91
104
|
const assets = platformAssets();
|
|
@@ -97,7 +110,7 @@ export async function ensureLivewareCli(
|
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
100
|
-
await downloadTo(LIVEWARE_BASE_URL + assets.liveware, path.join(dir,
|
|
113
|
+
await downloadTo(LIVEWARE_BASE_URL + assets.liveware, path.join(dir, name));
|
|
101
114
|
log?.debug?.(`clawchat-plugin-openclaw: liveware CLI downloaded to ${dir}`);
|
|
102
115
|
} catch (err) {
|
|
103
116
|
log?.warn?.(`clawchat-plugin-openclaw: liveware CLI download skipped: ${String(err)}`);
|
package/src/tools-schema.ts
CHANGED
|
@@ -201,6 +201,13 @@ export const ClawchatGetConversationSchema = Type.Object({
|
|
|
201
201
|
});
|
|
202
202
|
export type ClawchatGetConversationParams = Static<typeof ClawchatGetConversationSchema>;
|
|
203
203
|
|
|
204
|
+
export const ClawchatLeaveGroupSchema = Type.Object({
|
|
205
|
+
conversationId: Type.String({
|
|
206
|
+
description: "Concrete ClawChat group conversation id to leave",
|
|
207
|
+
}),
|
|
208
|
+
});
|
|
209
|
+
export type ClawchatLeaveGroupParams = Static<typeof ClawchatLeaveGroupSchema>;
|
|
210
|
+
|
|
204
211
|
export const ClawchatMentionMessageSchema = Type.Object({
|
|
205
212
|
chatId: Type.String({
|
|
206
213
|
minLength: 1,
|
package/src/tools.ts
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
ClawchatGetAccountProfileSchema,
|
|
42
42
|
ClawchatGetConversationSchema,
|
|
43
43
|
ClawchatGetUserProfileSchema,
|
|
44
|
+
ClawchatLeaveGroupSchema,
|
|
44
45
|
ClawchatAcceptFriendRequestSchema,
|
|
45
46
|
ClawchatMemoryEditSchema,
|
|
46
47
|
ClawchatMemoryReadSchema,
|
|
@@ -81,6 +82,7 @@ import {
|
|
|
81
82
|
type ClawchatAcceptFriendRequestParams,
|
|
82
83
|
type ClawchatGetConversationParams,
|
|
83
84
|
type ClawchatGetUserProfileParams,
|
|
85
|
+
type ClawchatLeaveGroupParams,
|
|
84
86
|
type ClawchatListFriendRequestsParams,
|
|
85
87
|
type ClawchatListMomentsParams,
|
|
86
88
|
type ClawchatMentionMessageParams,
|
|
@@ -1010,6 +1012,38 @@ export function registerOpenclawClawlingTools(
|
|
|
1010
1012
|
{ name: "clawchat_get_conversation" },
|
|
1011
1013
|
);
|
|
1012
1014
|
|
|
1015
|
+
api.registerTool(
|
|
1016
|
+
{
|
|
1017
|
+
name: "clawchat_leave_group",
|
|
1018
|
+
label: "Leave ClawChat Group",
|
|
1019
|
+
description: toolDescription(
|
|
1020
|
+
"Leave a ClawChat group conversation the agent is currently a member of. " +
|
|
1021
|
+
"TRIGGER - invoke only when the user explicitly asks the agent to leave, exit, or quit a specific ClawChat group and provides a concrete conversationId. " +
|
|
1022
|
+
"Groups only: direct conversations are rejected by the server. " +
|
|
1023
|
+
"If the agent is the group owner, leaving auto-transfers ownership to the earliest human member; if no human member remains, the group is dissolved. " +
|
|
1024
|
+
"After this tool succeeds, output only <clawchat:no-reply/> and do not send a normal follow-up reply.",
|
|
1025
|
+
),
|
|
1026
|
+
parameters: ClawchatLeaveGroupSchema,
|
|
1027
|
+
async execute(_callId, params) {
|
|
1028
|
+
return await recordClawchatToolCall("clawchat_leave_group", params, async () => {
|
|
1029
|
+
const p = params as ClawchatLeaveGroupParams;
|
|
1030
|
+
const built = buildClient();
|
|
1031
|
+
if (!built.ok) return built.error;
|
|
1032
|
+
try {
|
|
1033
|
+
const data = await built.client.leaveConversation(p.conversationId);
|
|
1034
|
+
return jsonResponse(data);
|
|
1035
|
+
} catch (err) {
|
|
1036
|
+
if (err instanceof ClawlingApiError) {
|
|
1037
|
+
return apiError(err);
|
|
1038
|
+
}
|
|
1039
|
+
return genericError(err);
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
},
|
|
1043
|
+
},
|
|
1044
|
+
{ name: "clawchat_leave_group" },
|
|
1045
|
+
);
|
|
1046
|
+
|
|
1013
1047
|
api.registerTool(
|
|
1014
1048
|
{
|
|
1015
1049
|
name: "clawchat_mention_message",
|