@clawling/clawchat-plugin-openclaw 2026.9.22-2 → 2026.9.23-2
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 +100 -3
- package/dist/src/skill-update.js +1 -1
- package/dist/src/tools-schema.js +51 -0
- package/dist/src/tools.js +254 -37
- package/openclaw.plugin.json +13 -1
- package/package.json +3 -1
- package/skills/clawchat-core/SKILL.md +9 -11
- package/skills/clawchat-orchestration/SKILL.md +60 -78
- package/skills/manifest.json +12 -12
- package/src/api-client.ts +140 -4
- package/src/skill-update.ts +1 -1
- package/src/tools-schema.ts +88 -0
- package/src/tools.ts +386 -36
package/dist/src/api-client.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { ClawlingApiError, } from "./api-types.js";
|
|
2
2
|
import { CHANNEL_ID } from "./config.js";
|
|
3
|
+
const ORCH = "/v1/agents/me/orchestration";
|
|
4
|
+
/** Body + content-type for an orchestration write, so the two never drift apart. */
|
|
5
|
+
function orchJson(payload) {
|
|
6
|
+
return { body: JSON.stringify(payload), headers: { "content-type": "application/json" } };
|
|
7
|
+
}
|
|
3
8
|
export function buildPluginReportBody(input) {
|
|
4
9
|
const body = {
|
|
5
10
|
device_id: input.deviceId,
|
|
@@ -264,8 +269,13 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
264
269
|
}
|
|
265
270
|
throw new ClawlingApiError("transport", text ? "invalid envelope: missing numeric `code`" : "non-JSON response: empty body", { status: res.status, path });
|
|
266
271
|
}
|
|
267
|
-
|
|
268
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Shared by `call<T>` and `orchCall`: build the request, invoke `fetchImpl`,
|
|
274
|
+
* and normalize any network-level failure into a `ClawlingApiError`. Kept
|
|
275
|
+
* as one function so the two callers' request-building can never drift
|
|
276
|
+
* apart again the way `call<T>` and `orchCall` briefly did.
|
|
277
|
+
*/
|
|
278
|
+
async function doFetch(method, path, init) {
|
|
269
279
|
try {
|
|
270
280
|
const requestInit = {
|
|
271
281
|
method,
|
|
@@ -274,13 +284,55 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
274
284
|
if (init?.body !== undefined) {
|
|
275
285
|
requestInit.body = init.body;
|
|
276
286
|
}
|
|
277
|
-
|
|
287
|
+
return await fetchImpl(url(path, init?.baseUrl || undefined), requestInit);
|
|
278
288
|
}
|
|
279
289
|
catch (err) {
|
|
280
290
|
throw new ClawlingApiError("transport", `fetch failed: ${err instanceof Error ? err.message : String(err)}`, { path });
|
|
281
291
|
}
|
|
292
|
+
}
|
|
293
|
+
async function call(method, path, init) {
|
|
294
|
+
const res = await doFetch(method, path, init);
|
|
282
295
|
return await readEnvelope(res, path);
|
|
283
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Orchestration routes (`${ORCH}/...`) are always HTTP 200 with the
|
|
299
|
+
* business code inside the envelope — a `21003` permission denial is a
|
|
300
|
+
* normal outcome there, not a transport failure. Unlike `call<T>`, this
|
|
301
|
+
* does NOT unwrap `data` or throw on a non-zero `code`; it hands back the
|
|
302
|
+
* parsed envelope exactly as received so the caller can branch on `code`
|
|
303
|
+
* itself.
|
|
304
|
+
*
|
|
305
|
+
* A 401/403 is checked FIRST, before any body parsing, exactly like
|
|
306
|
+
* `readEnvelope` — an expired/malformed token is not a business-code
|
|
307
|
+
* outcome and must throw `kind: "auth"` rather than fall through to the
|
|
308
|
+
* empty-body branch below and be misread as success. NOTE: on the
|
|
309
|
+
* orchestration tool path (`tools.ts` `buildClient` → a raw client,
|
|
310
|
+
* consumed via `withClient`) this throw is NOT retried — `withClient`
|
|
311
|
+
* turns any `ClawlingApiError` straight into `apiError(err)`. Reactive
|
|
312
|
+
* retry-after-refresh only exists behind `getConversationApiClient`'s
|
|
313
|
+
* `withRefresh` wrapper (`runtime.ts`), which the twelve `orch*` tools do
|
|
314
|
+
* not go through; this matches the other non-orchestration tools that
|
|
315
|
+
* build a raw client the same way. Proactive rotation is still picked up here for
|
|
316
|
+
* free, since the token is read fresh from the account at call time.
|
|
317
|
+
*/
|
|
318
|
+
async function orchCall(method, path, init) {
|
|
319
|
+
const res = await doFetch(method, path, init);
|
|
320
|
+
if (res.status === 401 || res.status === 403) {
|
|
321
|
+
throw new ClawlingApiError("auth", `unauthorized (status ${res.status})`, {
|
|
322
|
+
status: res.status,
|
|
323
|
+
path,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const text = await res.text().catch(() => "");
|
|
327
|
+
if (!text)
|
|
328
|
+
return undefined;
|
|
329
|
+
try {
|
|
330
|
+
return JSON.parse(text);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
throw new ClawlingApiError("transport", "non-JSON response", { status: res.status, path });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
284
336
|
function parseUploadResult(data, path) {
|
|
285
337
|
const obj = data;
|
|
286
338
|
const validKind = obj?.kind === "image" || obj?.kind === "file" || obj?.kind === "audio" || obj?.kind === "video";
|
|
@@ -376,6 +428,51 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
376
428
|
assertNonBlankId(friendUserId, "removeFriend: friendUserId");
|
|
377
429
|
return await call("DELETE", `/v1/friendships/${encodeURIComponent(friendUserId)}`);
|
|
378
430
|
},
|
|
431
|
+
async orchListAgents() {
|
|
432
|
+
return await orchCall("GET", `${ORCH}/agents`);
|
|
433
|
+
},
|
|
434
|
+
async orchGetAgent(agentId) {
|
|
435
|
+
return await orchCall("GET", `${ORCH}/agents/${encodeURIComponent(agentId)}`);
|
|
436
|
+
},
|
|
437
|
+
async orchSetAgentBehavior(agentId, behavior) {
|
|
438
|
+
return await orchCall("PATCH", `${ORCH}/agents/${encodeURIComponent(agentId)}`, orchJson({ behavior }));
|
|
439
|
+
},
|
|
440
|
+
async orchListGroups() {
|
|
441
|
+
return await orchCall("GET", `${ORCH}/groups`);
|
|
442
|
+
},
|
|
443
|
+
async orchGetGroup(cid) {
|
|
444
|
+
return await orchCall("GET", `${ORCH}/groups/${encodeURIComponent(cid)}`);
|
|
445
|
+
},
|
|
446
|
+
async orchSetGroupPrompt(cid, description) {
|
|
447
|
+
return await orchCall("PATCH", `${ORCH}/groups/${encodeURIComponent(cid)}`, orchJson({ description }));
|
|
448
|
+
},
|
|
449
|
+
async orchCreateGroup(title, agentIds) {
|
|
450
|
+
return await orchCall("POST", `${ORCH}/groups`, orchJson({ title, agent_ids: agentIds }));
|
|
451
|
+
},
|
|
452
|
+
async orchAddGroupMember(cid, agentId) {
|
|
453
|
+
return await orchCall("POST", `${ORCH}/groups/${encodeURIComponent(cid)}/members`, orchJson({ agent_id: agentId }));
|
|
454
|
+
},
|
|
455
|
+
async orchRemoveGroupMember(cid, agentId) {
|
|
456
|
+
return await orchCall("DELETE", `${ORCH}/groups/${encodeURIComponent(cid)}/members/${encodeURIComponent(agentId)}`);
|
|
457
|
+
},
|
|
458
|
+
async orchSetGroupAgentSettings(cid, agentId, patch) {
|
|
459
|
+
// `!== undefined` rather than truthiness: `muted: false` is a real value
|
|
460
|
+
// the backend must see; an absent key means "leave unchanged".
|
|
461
|
+
const body = {};
|
|
462
|
+
if (patch.muted !== undefined)
|
|
463
|
+
body.muted = patch.muted;
|
|
464
|
+
if (patch.replyMode !== undefined)
|
|
465
|
+
body.reply_mode = patch.replyMode;
|
|
466
|
+
if (patch.batchDelaySeconds !== undefined)
|
|
467
|
+
body.batch_delay_seconds = patch.batchDelaySeconds;
|
|
468
|
+
return await orchCall("PATCH", `${ORCH}/groups/${encodeURIComponent(cid)}/agents/${encodeURIComponent(agentId)}`, orchJson(body));
|
|
469
|
+
},
|
|
470
|
+
async orchCreateConnectCode() {
|
|
471
|
+
return await orchCall("POST", `${ORCH}/connect-codes`);
|
|
472
|
+
},
|
|
473
|
+
async orchGetConnectCode(code) {
|
|
474
|
+
return await orchCall("GET", `${ORCH}/connect-codes/${encodeURIComponent(code)}`);
|
|
475
|
+
},
|
|
379
476
|
async registerApp(params) {
|
|
380
477
|
assertNonBlankId(params.appId, "registerApp: appId");
|
|
381
478
|
return await call("POST", "/v1/agents/me/apps", {
|
package/dist/src/skill-update.js
CHANGED
|
@@ -66,7 +66,7 @@ export const OFFICIAL_SKILLS_BASE = "https://raw.githubusercontent.com/clawling/
|
|
|
66
66
|
* in the install-cli repo, bump this constant, ship it. `liveware-sample.ts`
|
|
67
67
|
* imports the same ref, so the `livewares` tree at that tag is pinned too.
|
|
68
68
|
*/
|
|
69
|
-
export const DEFAULT_SKILLS_REF = "skills-v1.
|
|
69
|
+
export const DEFAULT_SKILLS_REF = "skills-v1.15.0";
|
|
70
70
|
/** Refuse to treat an absurdly large response as a skill file (defence in depth). */
|
|
71
71
|
export const MAX_SKILL_BYTES = 256 * 1024;
|
|
72
72
|
/** This adapter's host target inside `skills/manifest.json`. */
|
package/dist/src/tools-schema.js
CHANGED
|
@@ -284,3 +284,54 @@ export const ClawchatUnregisterAppSchema = Type.Object({
|
|
|
284
284
|
appId: Type.String({ minLength: 1, description: "The liveware app id to unregister." }),
|
|
285
285
|
});
|
|
286
286
|
export const ClawchatLivewareLoginSchema = Type.Object({});
|
|
287
|
+
// --- cloud orchestration (`agent.orchestrate`) ----------------------------
|
|
288
|
+
// Twelve schemas, 1:1 with docs/features/agentorch.md.
|
|
289
|
+
const OrchAgentId = Type.String({
|
|
290
|
+
minLength: 1,
|
|
291
|
+
description: "Explicit agent id from clawchat_orchestrate_list_agents. Never guess one from a nickname.",
|
|
292
|
+
});
|
|
293
|
+
const OrchConversationId = Type.String({
|
|
294
|
+
minLength: 1,
|
|
295
|
+
description: "Explicit group conversation id from clawchat_orchestrate_list_groups.",
|
|
296
|
+
});
|
|
297
|
+
export const ClawchatOrchListAgentsSchema = Type.Object({}, { additionalProperties: false });
|
|
298
|
+
export const ClawchatOrchGetAgentSchema = Type.Object({ agentId: OrchAgentId }, { additionalProperties: false });
|
|
299
|
+
export const ClawchatOrchSetAgentBehaviorSchema = Type.Object({
|
|
300
|
+
agentId: OrchAgentId,
|
|
301
|
+
behavior: Type.String({
|
|
302
|
+
maxLength: 3000,
|
|
303
|
+
description: "The complete new system prompt. REPLACES the whole field — GET first and send the full value.",
|
|
304
|
+
}),
|
|
305
|
+
}, { additionalProperties: false });
|
|
306
|
+
export const ClawchatOrchListGroupsSchema = Type.Object({}, { additionalProperties: false });
|
|
307
|
+
export const ClawchatOrchGetGroupSchema = Type.Object({ conversationId: OrchConversationId }, { additionalProperties: false });
|
|
308
|
+
export const ClawchatOrchSetGroupPromptSchema = Type.Object({
|
|
309
|
+
conversationId: OrchConversationId,
|
|
310
|
+
description: Type.String({
|
|
311
|
+
maxLength: 3000,
|
|
312
|
+
description: "The complete new group system prompt. REPLACES the whole field.",
|
|
313
|
+
}),
|
|
314
|
+
}, { additionalProperties: false });
|
|
315
|
+
export const ClawchatOrchCreateGroupSchema = Type.Object({
|
|
316
|
+
title: Type.String({ minLength: 1, maxLength: 60, description: "Group title, 1-60 runes." }),
|
|
317
|
+
agentIds: Type.Array(Type.String({ minLength: 1 }), {
|
|
318
|
+
minItems: 1,
|
|
319
|
+
description: "Agent ids from clawchat_orchestrate_list_agents. Must be the owner's own agents.",
|
|
320
|
+
}),
|
|
321
|
+
}, { additionalProperties: false });
|
|
322
|
+
export const ClawchatOrchGroupMemberSchema = Type.Object({ conversationId: OrchConversationId, agentId: OrchAgentId }, { additionalProperties: false });
|
|
323
|
+
export const ClawchatOrchSetGroupAgentSettingsSchema = Type.Object({
|
|
324
|
+
conversationId: OrchConversationId,
|
|
325
|
+
agentId: OrchAgentId,
|
|
326
|
+
muted: Type.Optional(Type.Boolean({ description: "Mute or unmute this agent in this group." })),
|
|
327
|
+
replyMode: Type.Optional(Type.Union([Type.Literal("all"), Type.Literal("mention")], {
|
|
328
|
+
description: "all = speaks on every message; mention = only when @-mentioned.",
|
|
329
|
+
})),
|
|
330
|
+
batchDelaySeconds: Type.Optional(Type.Integer({
|
|
331
|
+
minimum: 1,
|
|
332
|
+
maximum: 3600,
|
|
333
|
+
description: "Seconds this agent batches messages before replying. Default 10. Pacing, not a limit.",
|
|
334
|
+
})),
|
|
335
|
+
}, { additionalProperties: false, minProperties: 3 });
|
|
336
|
+
export const ClawchatOrchCreateConnectCodeSchema = Type.Object({}, { additionalProperties: false });
|
|
337
|
+
export const ClawchatOrchGetConnectCodeSchema = Type.Object({ code: Type.String({ minLength: 1, description: "The connect code to look up." }) }, { additionalProperties: false });
|