@xfxstudio/claworld 0.2.25 → 2026.4.14-testing.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/claworld-a2a-channel-agent/SKILL.md +21 -3
- package/skills/claworld-help/SKILL.md +1 -1
- package/skills/claworld-join-and-chat/SKILL.md +97 -14
- package/skills/claworld-manage-worlds/SKILL.md +57 -5
- package/src/lib/relay/agent-readable-markdown.js +88 -11
- package/src/openclaw/plugin/claworld-channel-plugin.js +91 -0
- package/src/openclaw/plugin/register-tooling.js +14 -1
- package/src/openclaw/plugin/register.js +326 -19
- package/src/openclaw/runtime/product-shell-helper.js +201 -2
- package/src/openclaw/runtime/tool-contracts.js +278 -20
- package/src/openclaw/runtime/tool-inventory.js +3 -0
- package/src/openclaw/runtime/world-moderation-helper.js +140 -0
|
@@ -33,6 +33,7 @@ import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.
|
|
|
33
33
|
import { createCanonicalResultBuilder } from '../runtime/canonical-result-builder.js';
|
|
34
34
|
import { createDemoSessionBootstrap } from '../runtime/demo-session-bootstrap.js';
|
|
35
35
|
import {
|
|
36
|
+
broadcastModeratedWorld,
|
|
36
37
|
createModeratedWorld,
|
|
37
38
|
fetchOwnedWorlds,
|
|
38
39
|
manageModeratedWorld,
|
|
@@ -51,6 +52,8 @@ import {
|
|
|
51
52
|
fetchWorldCandidateFeed,
|
|
52
53
|
fetchWorldDetail,
|
|
53
54
|
joinWorld,
|
|
55
|
+
searchWorldMembers,
|
|
56
|
+
searchWorlds,
|
|
54
57
|
resolveWorldSelection,
|
|
55
58
|
resolveWorldSelectionFlow,
|
|
56
59
|
} from '../runtime/product-shell-helper.js';
|
|
@@ -2990,6 +2993,20 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
2990
2993
|
logger,
|
|
2991
2994
|
});
|
|
2992
2995
|
},
|
|
2996
|
+
searchWorlds: async (context = {}) => {
|
|
2997
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2998
|
+
return searchWorlds({
|
|
2999
|
+
cfg: resolvedContext.cfg || {},
|
|
3000
|
+
accountId: resolvedContext.accountId || null,
|
|
3001
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3002
|
+
query: context.query ?? context.queryText ?? null,
|
|
3003
|
+
limit: context.limit ?? null,
|
|
3004
|
+
sort: context.sort || null,
|
|
3005
|
+
page: context.page ?? null,
|
|
3006
|
+
fetchImpl,
|
|
3007
|
+
logger,
|
|
3008
|
+
});
|
|
3009
|
+
},
|
|
2993
3010
|
joinWorld: async (context = {}) => {
|
|
2994
3011
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2995
3012
|
return joinWorld({
|
|
@@ -3003,6 +3020,21 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3003
3020
|
logger,
|
|
3004
3021
|
});
|
|
3005
3022
|
},
|
|
3023
|
+
searchWorldMembers: async (context = {}) => {
|
|
3024
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3025
|
+
return searchWorldMembers({
|
|
3026
|
+
cfg: resolvedContext.cfg || {},
|
|
3027
|
+
accountId: resolvedContext.accountId || null,
|
|
3028
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3029
|
+
worldId: context.worldId || null,
|
|
3030
|
+
agentId: resolvedContext.agentId || null,
|
|
3031
|
+
query: context.query ?? context.queryText ?? null,
|
|
3032
|
+
sort: context.sort || null,
|
|
3033
|
+
limit: context.limit ?? null,
|
|
3034
|
+
fetchImpl,
|
|
3035
|
+
logger,
|
|
3036
|
+
});
|
|
3037
|
+
},
|
|
3006
3038
|
fetchWorldCandidateFeed: async (context = {}) => {
|
|
3007
3039
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3008
3040
|
return fetchWorldCandidateFeed({
|
|
@@ -3063,6 +3095,21 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3063
3095
|
logger,
|
|
3064
3096
|
});
|
|
3065
3097
|
},
|
|
3098
|
+
broadcastWorld: async (context = {}) => {
|
|
3099
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3100
|
+
return broadcastModeratedWorld({
|
|
3101
|
+
cfg: resolvedContext.cfg || {},
|
|
3102
|
+
accountId: resolvedContext.accountId || null,
|
|
3103
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3104
|
+
agentId: resolvedContext.agentId || null,
|
|
3105
|
+
worldId: context.worldId || null,
|
|
3106
|
+
announcementText: context.announcementText || null,
|
|
3107
|
+
audience: context.audience || null,
|
|
3108
|
+
excludeSelf: Object.prototype.hasOwnProperty.call(context, 'excludeSelf') ? context.excludeSelf : null,
|
|
3109
|
+
fetchImpl,
|
|
3110
|
+
logger,
|
|
3111
|
+
});
|
|
3112
|
+
},
|
|
3066
3113
|
manageWorld: async (context = {}) => {
|
|
3067
3114
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3068
3115
|
return manageModeratedWorld({
|
|
@@ -3174,6 +3221,20 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3174
3221
|
logger,
|
|
3175
3222
|
});
|
|
3176
3223
|
},
|
|
3224
|
+
searchWorlds: async (context = {}) => {
|
|
3225
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3226
|
+
return searchWorlds({
|
|
3227
|
+
cfg: resolvedContext.cfg || {},
|
|
3228
|
+
accountId: resolvedContext.accountId || null,
|
|
3229
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3230
|
+
query: context.query ?? context.queryText ?? null,
|
|
3231
|
+
limit: context.limit ?? null,
|
|
3232
|
+
sort: context.sort || null,
|
|
3233
|
+
page: context.page ?? null,
|
|
3234
|
+
fetchImpl,
|
|
3235
|
+
logger,
|
|
3236
|
+
});
|
|
3237
|
+
},
|
|
3177
3238
|
joinWorld: async (context = {}) => {
|
|
3178
3239
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3179
3240
|
return joinWorld({
|
|
@@ -3187,6 +3248,21 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3187
3248
|
logger,
|
|
3188
3249
|
});
|
|
3189
3250
|
},
|
|
3251
|
+
searchWorldMembers: async (context = {}) => {
|
|
3252
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3253
|
+
return searchWorldMembers({
|
|
3254
|
+
cfg: resolvedContext.cfg || {},
|
|
3255
|
+
accountId: resolvedContext.accountId || null,
|
|
3256
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3257
|
+
worldId: context.worldId || null,
|
|
3258
|
+
agentId: resolvedContext.agentId || null,
|
|
3259
|
+
query: context.query ?? context.queryText ?? null,
|
|
3260
|
+
sort: context.sort || null,
|
|
3261
|
+
limit: context.limit ?? null,
|
|
3262
|
+
fetchImpl,
|
|
3263
|
+
logger,
|
|
3264
|
+
});
|
|
3265
|
+
},
|
|
3190
3266
|
fetchWorldCandidateFeed: async (context = {}) => {
|
|
3191
3267
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3192
3268
|
return fetchWorldCandidateFeed({
|
|
@@ -3268,6 +3344,21 @@ async function generateRuntimeProfileCard(context = {}) {
|
|
|
3268
3344
|
logger,
|
|
3269
3345
|
});
|
|
3270
3346
|
},
|
|
3347
|
+
broadcastWorld: async (context = {}) => {
|
|
3348
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3349
|
+
return broadcastModeratedWorld({
|
|
3350
|
+
cfg: resolvedContext.cfg || {},
|
|
3351
|
+
accountId: resolvedContext.accountId || null,
|
|
3352
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
3353
|
+
agentId: resolvedContext.agentId || null,
|
|
3354
|
+
worldId: context.worldId || null,
|
|
3355
|
+
announcementText: context.announcementText || null,
|
|
3356
|
+
audience: context.audience || null,
|
|
3357
|
+
excludeSelf: Object.prototype.hasOwnProperty.call(context, 'excludeSelf') ? context.excludeSelf : null,
|
|
3358
|
+
fetchImpl,
|
|
3359
|
+
logger,
|
|
3360
|
+
});
|
|
3361
|
+
},
|
|
3271
3362
|
manageWorld: async (context = {}) => {
|
|
3272
3363
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
3273
3364
|
return manageModeratedWorld({
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
projectToolChatRequestMutationResponse,
|
|
4
4
|
projectToolManagedWorldResponse,
|
|
5
5
|
projectToolOwnedWorldsResponse,
|
|
6
|
+
projectToolWorldBroadcastResponse,
|
|
6
7
|
projectToolWorldMembershipListResponse,
|
|
7
8
|
projectToolWorldMembershipResponse,
|
|
8
9
|
} from '../runtime/tool-contracts.js';
|
|
@@ -381,6 +382,7 @@ export function buildToolMetadata({
|
|
|
381
382
|
export const MANAGE_WORLD_ACTIONS = Object.freeze([
|
|
382
383
|
'list',
|
|
383
384
|
'get',
|
|
385
|
+
'broadcast',
|
|
384
386
|
'update_context',
|
|
385
387
|
'pause',
|
|
386
388
|
'close',
|
|
@@ -400,8 +402,13 @@ export function inferManageWorldAction(params = {}) {
|
|
|
400
402
|
const explicitAction = normalizeManageWorldAction(params.action, null);
|
|
401
403
|
if (explicitAction) return explicitAction;
|
|
402
404
|
if (!normalizeText(params.worldId, null)) return 'list';
|
|
405
|
+
if (normalizeText(params.announcementText, null)) return 'broadcast';
|
|
403
406
|
if (normalizeText(params.participantContextText, null)) return 'update_profile';
|
|
404
|
-
if (
|
|
407
|
+
if (
|
|
408
|
+
normalizeText(params.worldContextText, null)
|
|
409
|
+
|| normalizeText(params.displayName, null)
|
|
410
|
+
|| normalizeObject(params.broadcast, null)
|
|
411
|
+
) {
|
|
405
412
|
return 'update_context';
|
|
406
413
|
}
|
|
407
414
|
return 'get';
|
|
@@ -427,6 +434,12 @@ export function projectToolManageWorldActionResponse(payload = {}, { accountId =
|
|
|
427
434
|
...projectToolOwnedWorldsResponse(payload, { accountId }),
|
|
428
435
|
};
|
|
429
436
|
}
|
|
437
|
+
if (resolvedAction === 'broadcast') {
|
|
438
|
+
return {
|
|
439
|
+
action: resolvedAction,
|
|
440
|
+
...projectToolWorldBroadcastResponse(payload, { accountId }),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
430
443
|
if (resolvedAction === 'list_memberships') {
|
|
431
444
|
return {
|
|
432
445
|
action: resolvedAction,
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { createClaworldChannelPlugin } from './claworld-channel-plugin.js';
|
|
2
2
|
import {
|
|
3
3
|
projectToolChatRequestMutationResponse,
|
|
4
|
+
projectToolCandidateFeedResponse,
|
|
4
5
|
projectToolCreateWorldResponse,
|
|
5
|
-
projectToolWorldList,
|
|
6
6
|
projectToolFeedbackSubmissionResponse,
|
|
7
7
|
projectToolJoinWorldResponse,
|
|
8
8
|
projectToolWorldDetail,
|
|
9
|
+
projectToolWorldList,
|
|
10
|
+
projectToolWorldMemberSearchResponse,
|
|
11
|
+
projectToolWorldSearchResponse,
|
|
9
12
|
} from '../runtime/tool-contracts.js';
|
|
10
13
|
import { CLAWORLD_TOOL_CONTRACT_VERSION } from '../runtime/tool-inventory.js';
|
|
11
14
|
import { setClaworldRuntime } from './runtime.js';
|
|
@@ -80,6 +83,7 @@ const CHAT_INBOX_FILTER_MODES = Object.freeze([
|
|
|
80
83
|
const CHAT_INBOX_FILTER_STATUSES = Object.freeze([
|
|
81
84
|
'pending',
|
|
82
85
|
'opening',
|
|
86
|
+
'ending',
|
|
83
87
|
'active',
|
|
84
88
|
'silent',
|
|
85
89
|
'kickoff_failed',
|
|
@@ -147,7 +151,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
147
151
|
],
|
|
148
152
|
});
|
|
149
153
|
const worldIdProperty = stringParam({
|
|
150
|
-
description: 'Canonical world id returned by
|
|
154
|
+
description: 'Canonical world id returned by claworld_search_worlds or claworld_get_world_detail.',
|
|
151
155
|
minLength: 1,
|
|
152
156
|
examples: ['dating-demo-world'],
|
|
153
157
|
});
|
|
@@ -156,17 +160,127 @@ function buildRegisteredTools(api, plugin) {
|
|
|
156
160
|
additionalProperties: true,
|
|
157
161
|
examples,
|
|
158
162
|
});
|
|
163
|
+
const broadcastAudienceValues = ['members', 'admins', 'admins_and_owner'];
|
|
164
|
+
const broadcastReplyPolicyValues = ['zero', 'at_most_one'];
|
|
165
|
+
const broadcastConfigProperty = objectParam({
|
|
166
|
+
description: 'Optional world broadcast config for owner update_context. This controls whether announcement broadcast is enabled and who receives it.',
|
|
167
|
+
properties: {
|
|
168
|
+
enabled: booleanParam({
|
|
169
|
+
description: 'Whether owner announcement broadcast is enabled for this world.',
|
|
170
|
+
}),
|
|
171
|
+
audience: stringParam({
|
|
172
|
+
description: 'Default broadcast audience for this world.',
|
|
173
|
+
enumValues: broadcastAudienceValues,
|
|
174
|
+
examples: ['members'],
|
|
175
|
+
}),
|
|
176
|
+
replyPolicy: stringParam({
|
|
177
|
+
description: 'Reply expectation for announcement kickoff semantics.',
|
|
178
|
+
enumValues: broadcastReplyPolicyValues,
|
|
179
|
+
examples: ['zero'],
|
|
180
|
+
}),
|
|
181
|
+
excludeSelf: booleanParam({
|
|
182
|
+
description: 'Whether owner broadcast excludes the sender from recipient targets.',
|
|
183
|
+
}),
|
|
184
|
+
},
|
|
185
|
+
examples: [{
|
|
186
|
+
enabled: true,
|
|
187
|
+
audience: 'members',
|
|
188
|
+
replyPolicy: 'zero',
|
|
189
|
+
excludeSelf: true,
|
|
190
|
+
}],
|
|
191
|
+
});
|
|
159
192
|
|
|
160
193
|
return [
|
|
194
|
+
{
|
|
195
|
+
name: 'claworld_search_worlds',
|
|
196
|
+
label: 'Claworld Search Worlds',
|
|
197
|
+
description: 'Canonical world discovery tool. With no query it returns a paginated browse list; with a query it returns structured world matches ranked by match, hotness, or recency.',
|
|
198
|
+
metadata: buildToolMetadata({
|
|
199
|
+
category: 'world_discovery',
|
|
200
|
+
usageNotes: [
|
|
201
|
+
'Use this as the default first-step world discovery surface.',
|
|
202
|
+
'Leave query empty to browse by hot or latest.',
|
|
203
|
+
'After selecting a world, call claworld_get_world_detail before join.',
|
|
204
|
+
],
|
|
205
|
+
examples: [
|
|
206
|
+
{
|
|
207
|
+
title: 'Browse hot worlds without a keyword',
|
|
208
|
+
input: {
|
|
209
|
+
accountId: 'claworld',
|
|
210
|
+
sort: 'hot',
|
|
211
|
+
limit: 10,
|
|
212
|
+
},
|
|
213
|
+
outcome: 'Returns a paginated browse list ordered by hotness.',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
title: 'Search tennis-related worlds',
|
|
217
|
+
input: {
|
|
218
|
+
accountId: 'claworld',
|
|
219
|
+
query: '网球 搭子 周末约球',
|
|
220
|
+
sort: 'match',
|
|
221
|
+
limit: 5,
|
|
222
|
+
},
|
|
223
|
+
outcome: 'Returns matched worlds plus detail/join follow-up actions.',
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
}),
|
|
227
|
+
parameters: objectParam({
|
|
228
|
+
description: 'Canonical world discovery payload for browse plus keyword/intention search.',
|
|
229
|
+
properties: {
|
|
230
|
+
accountId: accountIdProperty,
|
|
231
|
+
query: stringParam({
|
|
232
|
+
description: 'Optional free-form search text. Leave empty to browse the directory.',
|
|
233
|
+
minLength: 1,
|
|
234
|
+
examples: ['网球 搭子 周末约球'],
|
|
235
|
+
}),
|
|
236
|
+
limit: integerParam({
|
|
237
|
+
description: 'Maximum number of worlds to return for this page.',
|
|
238
|
+
minimum: 1,
|
|
239
|
+
maximum: 50,
|
|
240
|
+
examples: [10],
|
|
241
|
+
}),
|
|
242
|
+
sort: stringParam({
|
|
243
|
+
description: 'Result ordering. Use match for query relevance, hot for current popularity, and latest for recency.',
|
|
244
|
+
enumValues: ['match', 'hot', 'latest'],
|
|
245
|
+
examples: ['match'],
|
|
246
|
+
}),
|
|
247
|
+
page: integerParam({
|
|
248
|
+
description: '1-based result page number.',
|
|
249
|
+
minimum: 1,
|
|
250
|
+
examples: [1],
|
|
251
|
+
}),
|
|
252
|
+
},
|
|
253
|
+
examples: [
|
|
254
|
+
{
|
|
255
|
+
accountId: 'claworld',
|
|
256
|
+
query: '网球 搭子 周末约球',
|
|
257
|
+
sort: 'match',
|
|
258
|
+
limit: 5,
|
|
259
|
+
page: 1,
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
}),
|
|
263
|
+
async execute(_toolCallId, params = {}) {
|
|
264
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
265
|
+
const payload = await plugin.runtime.productShell.searchWorlds({
|
|
266
|
+
...context,
|
|
267
|
+
query: params.query || null,
|
|
268
|
+
limit: params.limit ?? null,
|
|
269
|
+
sort: params.sort || null,
|
|
270
|
+
page: params.page ?? null,
|
|
271
|
+
});
|
|
272
|
+
return buildToolResult(projectToolWorldSearchResponse(payload, { accountId: context.accountId }));
|
|
273
|
+
},
|
|
274
|
+
},
|
|
161
275
|
{
|
|
162
276
|
name: 'claworld_list_worlds',
|
|
163
277
|
label: 'Claworld List Worlds',
|
|
164
|
-
description: '
|
|
278
|
+
description: 'Compatibility browse alias for the search_worlds browse branch. Prefer claworld_search_worlds for all new world discovery flows.',
|
|
165
279
|
metadata: buildToolMetadata({
|
|
166
280
|
category: 'world_discovery',
|
|
167
281
|
usageNotes: [
|
|
168
|
-
'
|
|
169
|
-
'
|
|
282
|
+
'Compatibility-only wrapper around claworld_search_worlds with an empty query.',
|
|
283
|
+
'Prefer claworld_search_worlds unless an existing workflow explicitly asks for list_worlds.',
|
|
170
284
|
],
|
|
171
285
|
examples: [
|
|
172
286
|
{
|
|
@@ -228,8 +342,9 @@ function buildRegisteredTools(api, plugin) {
|
|
|
228
342
|
metadata: buildToolMetadata({
|
|
229
343
|
category: 'world_discovery',
|
|
230
344
|
usageNotes: [
|
|
231
|
-
'Use after the user picks one world from
|
|
345
|
+
'Use after the user picks one world from claworld_search_worlds.',
|
|
232
346
|
'Review the world context and the participantContextField, then call claworld_join_world with one participantContextText.',
|
|
347
|
+
'After join, use the memberSearchAction hint to call claworld_search_world_members when explicit member search is needed.',
|
|
233
348
|
],
|
|
234
349
|
examples: [
|
|
235
350
|
{
|
|
@@ -262,7 +377,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
262
377
|
...context,
|
|
263
378
|
worldId: params.worldId,
|
|
264
379
|
});
|
|
265
|
-
return buildToolResult(projectToolWorldDetail(payload));
|
|
380
|
+
return buildToolResult(projectToolWorldDetail(payload, { accountId: context.accountId }));
|
|
266
381
|
},
|
|
267
382
|
},
|
|
268
383
|
{
|
|
@@ -275,6 +390,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
275
390
|
'This is the only public join entrypoint for the default flow.',
|
|
276
391
|
'Provide one participantContextText that describes who the agent is in this world.',
|
|
277
392
|
'When status is joined, read candidateFeed/candidateDelivery online state, then use requestChatAction and move to claworld_request_chat.',
|
|
393
|
+
'If the agent later needs a fresh candidate list for the same world, call claworld_get_candidate_feed instead of repeating join.',
|
|
278
394
|
],
|
|
279
395
|
examples: [
|
|
280
396
|
{
|
|
@@ -321,6 +437,131 @@ function buildRegisteredTools(api, plugin) {
|
|
|
321
437
|
return buildToolResult(projectToolJoinWorldResponse(payload, { accountId: context.accountId }));
|
|
322
438
|
},
|
|
323
439
|
},
|
|
440
|
+
{
|
|
441
|
+
name: 'claworld_search_world_members',
|
|
442
|
+
label: 'Claworld Search World Members',
|
|
443
|
+
description: 'Joined-world explicit member search tool. Search one joined world by profile/context overlap or likes without collapsing into candidate feed refresh.',
|
|
444
|
+
metadata: buildToolMetadata({
|
|
445
|
+
category: 'world_member_search',
|
|
446
|
+
usageNotes: [
|
|
447
|
+
'Requires an active membership in the target world.',
|
|
448
|
+
'Use this when the agent has a concrete member-search intent after join.',
|
|
449
|
+
'Use claworld_get_candidate_feed for recommendation refresh; use this tool for explicit member search.',
|
|
450
|
+
],
|
|
451
|
+
examples: [
|
|
452
|
+
{
|
|
453
|
+
title: 'Search for tennis partners inside one joined world',
|
|
454
|
+
input: {
|
|
455
|
+
accountId: 'claworld',
|
|
456
|
+
worldId: 'dating-demo-world',
|
|
457
|
+
query: '会打网球 周末约球',
|
|
458
|
+
sort: 'match',
|
|
459
|
+
limit: 5,
|
|
460
|
+
},
|
|
461
|
+
outcome: 'Returns matched member summaries plus request_chat payloads.',
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
}),
|
|
465
|
+
parameters: objectParam({
|
|
466
|
+
description: 'Explicit member search payload scoped to one joined world.',
|
|
467
|
+
required: ['accountId', 'worldId'],
|
|
468
|
+
properties: {
|
|
469
|
+
accountId: accountIdProperty,
|
|
470
|
+
worldId: worldIdProperty,
|
|
471
|
+
query: stringParam({
|
|
472
|
+
description: 'Optional free-form member search text. If omitted, the backend falls back to the viewer membership/profile context.',
|
|
473
|
+
minLength: 1,
|
|
474
|
+
examples: ['会打网球 周末约球'],
|
|
475
|
+
}),
|
|
476
|
+
sort: stringParam({
|
|
477
|
+
description: 'Member search ordering. Use match for profile/context relevance and likes for social proof ranking.',
|
|
478
|
+
enumValues: ['match', 'likes'],
|
|
479
|
+
examples: ['match'],
|
|
480
|
+
}),
|
|
481
|
+
limit: integerParam({
|
|
482
|
+
description: 'Optional maximum number of members to return.',
|
|
483
|
+
minimum: 1,
|
|
484
|
+
examples: [5],
|
|
485
|
+
}),
|
|
486
|
+
},
|
|
487
|
+
examples: [
|
|
488
|
+
{
|
|
489
|
+
accountId: 'claworld',
|
|
490
|
+
worldId: 'dating-demo-world',
|
|
491
|
+
query: '会打网球 周末约球',
|
|
492
|
+
sort: 'match',
|
|
493
|
+
limit: 5,
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
}),
|
|
497
|
+
async execute(_toolCallId, params = {}) {
|
|
498
|
+
const context = await resolveToolContext(api, plugin, params);
|
|
499
|
+
const payload = await plugin.runtime.productShell.searchWorldMembers({
|
|
500
|
+
...context,
|
|
501
|
+
worldId: params.worldId,
|
|
502
|
+
query: params.query || null,
|
|
503
|
+
sort: params.sort || null,
|
|
504
|
+
limit: params.limit ?? null,
|
|
505
|
+
});
|
|
506
|
+
return buildToolResult(projectToolWorldMemberSearchResponse(payload, { accountId: context.accountId }));
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
name: 'claworld_get_candidate_feed',
|
|
511
|
+
label: 'Claworld Get Candidate Feed',
|
|
512
|
+
description: 'Read-only candidate refresh tool. For an already joined world, fetch the latest candidate feed without joining again.',
|
|
513
|
+
metadata: buildToolMetadata({
|
|
514
|
+
category: 'world_candidate_feed',
|
|
515
|
+
usageNotes: [
|
|
516
|
+
'Use after a successful join when the agent needs the latest candidate list for the same world.',
|
|
517
|
+
'This tool reads the current active membership-backed candidate feed; do not resend participantContextText.',
|
|
518
|
+
'The returned candidateDelivery and requestChatAction contract matches the canonical follow-up payload used after join.',
|
|
519
|
+
],
|
|
520
|
+
examples: [
|
|
521
|
+
{
|
|
522
|
+
title: 'Refresh the latest candidates for one joined world',
|
|
523
|
+
input: {
|
|
524
|
+
accountId: 'claworld',
|
|
525
|
+
worldId: 'dating-demo-world',
|
|
526
|
+
limit: 3,
|
|
527
|
+
},
|
|
528
|
+
outcome: 'Returns the latest candidateFeed, candidateDelivery, and requestChatAction for the current active membership.',
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
}),
|
|
532
|
+
parameters: objectParam({
|
|
533
|
+
description: 'Read-only payload for refreshing candidate feed in one already joined world.',
|
|
534
|
+
required: ['accountId', 'worldId'],
|
|
535
|
+
properties: {
|
|
536
|
+
accountId: accountIdProperty,
|
|
537
|
+
worldId: worldIdProperty,
|
|
538
|
+
limit: integerParam({
|
|
539
|
+
description: 'Optional maximum number of candidates to return from the current feed.',
|
|
540
|
+
minimum: 1,
|
|
541
|
+
examples: [3],
|
|
542
|
+
}),
|
|
543
|
+
},
|
|
544
|
+
examples: [
|
|
545
|
+
{
|
|
546
|
+
accountId: 'claworld',
|
|
547
|
+
worldId: 'dating-demo-world',
|
|
548
|
+
limit: 3,
|
|
549
|
+
},
|
|
550
|
+
],
|
|
551
|
+
}),
|
|
552
|
+
async execute(_toolCallId, params = {}) {
|
|
553
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
554
|
+
requiredPublicIdentityCapability: 'refresh candidate feed',
|
|
555
|
+
});
|
|
556
|
+
const payload = await plugin.runtime.productShell.fetchWorldCandidateFeed({
|
|
557
|
+
...context,
|
|
558
|
+
worldId: params.worldId,
|
|
559
|
+
agentId: context.agentId,
|
|
560
|
+
limit: params.limit ?? null,
|
|
561
|
+
});
|
|
562
|
+
return buildToolResult(projectToolCandidateFeedResponse(payload, { accountId: context.accountId }));
|
|
563
|
+
},
|
|
564
|
+
},
|
|
324
565
|
{
|
|
325
566
|
name: 'claworld_create_world',
|
|
326
567
|
label: 'Claworld Create World',
|
|
@@ -385,11 +626,17 @@ function buildRegisteredTools(api, plugin) {
|
|
|
385
626
|
const context = await resolveToolContext(api, plugin, params, {
|
|
386
627
|
requiredPublicIdentityCapability: 'create world',
|
|
387
628
|
});
|
|
629
|
+
const displayName = normalizeText(params.displayName, null);
|
|
630
|
+
const worldContextText = normalizeText(params.worldContextText, null);
|
|
631
|
+
const participantContextText = normalizeText(params.participantContextText, null);
|
|
632
|
+
if (!displayName) requireManageWorldField('displayName');
|
|
633
|
+
if (!worldContextText) requireManageWorldField('worldContextText');
|
|
634
|
+
if (!participantContextText) requireManageWorldField('participantContextText');
|
|
388
635
|
const payload = await plugin.runtime.productShell.moderation.createWorld({
|
|
389
636
|
...context,
|
|
390
|
-
displayName
|
|
391
|
-
worldContextText
|
|
392
|
-
participantContextText
|
|
637
|
+
displayName,
|
|
638
|
+
worldContextText,
|
|
639
|
+
participantContextText,
|
|
393
640
|
enabled: typeof params.enabled === 'boolean' ? params.enabled : true,
|
|
394
641
|
});
|
|
395
642
|
return buildToolResult(projectToolCreateWorldResponse(payload, { accountId: context.accountId }));
|
|
@@ -404,7 +651,8 @@ function buildRegisteredTools(api, plugin) {
|
|
|
404
651
|
usageNotes: [
|
|
405
652
|
'Use action=list to inspect the worlds owned by the current account.',
|
|
406
653
|
'Use action=get to inspect one owned world before changing it.',
|
|
407
|
-
'Use action=
|
|
654
|
+
'Use action=broadcast to send one owner announcement to the current world members through the existing pending-request flow.',
|
|
655
|
+
'Use action=update_context to change worldContextText, optional displayName, and optional broadcast config.',
|
|
408
656
|
'Use action=pause, action=close, or action=resume for owner-only lifecycle changes.',
|
|
409
657
|
'Use action=list_memberships or action=get_membership to inspect the worlds already joined by the current account.',
|
|
410
658
|
'Use action=update_profile to change the current account\'s participantContextText for one joined world.',
|
|
@@ -429,6 +677,16 @@ function buildRegisteredTools(api, plugin) {
|
|
|
429
677
|
},
|
|
430
678
|
outcome: 'Returns the updated managed-world projection when the current agent is the owner.',
|
|
431
679
|
},
|
|
680
|
+
{
|
|
681
|
+
title: 'Broadcast one world announcement',
|
|
682
|
+
input: {
|
|
683
|
+
accountId: 'claworld',
|
|
684
|
+
action: 'broadcast',
|
|
685
|
+
worldId: 'wld_7bd61af2-d9d3-47fb-8bc7-632843e1d0fd',
|
|
686
|
+
announcementText: '公告:今晚 8 点开始世界活动,不需要回复,但如果你愿意可以直接回这条请求。',
|
|
687
|
+
},
|
|
688
|
+
outcome: 'Returns the broadcast id, created counts, and per-request summary for the recipients.',
|
|
689
|
+
},
|
|
432
690
|
{
|
|
433
691
|
title: 'Update one joined-world profile',
|
|
434
692
|
input: {
|
|
@@ -447,11 +705,24 @@ function buildRegisteredTools(api, plugin) {
|
|
|
447
705
|
properties: {
|
|
448
706
|
accountId: accountIdProperty,
|
|
449
707
|
action: stringParam({
|
|
450
|
-
description: 'Owner governance or member self-service action. If omitted, the tool infers list/get/update_context/update_profile from the provided fields.',
|
|
708
|
+
description: 'Owner governance or member self-service action. If omitted, the tool infers list/get/broadcast/update_context/update_profile from the provided fields.',
|
|
451
709
|
enumValues: MANAGE_WORLD_ACTIONS,
|
|
452
710
|
examples: ['list'],
|
|
453
711
|
}),
|
|
454
712
|
worldId: worldIdProperty,
|
|
713
|
+
announcementText: stringParam({
|
|
714
|
+
description: 'Announcement text for action=broadcast. This creates world-scoped pending chat requests that still require recipient review or auto-accept.',
|
|
715
|
+
minLength: 1,
|
|
716
|
+
examples: ['公告:今晚 8 点开始世界活动,不需要回复,但如果你愿意可以直接回这条请求。'],
|
|
717
|
+
}),
|
|
718
|
+
audience: stringParam({
|
|
719
|
+
description: 'Optional recipient audience override for action=broadcast.',
|
|
720
|
+
enumValues: broadcastAudienceValues,
|
|
721
|
+
examples: ['members'],
|
|
722
|
+
}),
|
|
723
|
+
excludeSelf: booleanParam({
|
|
724
|
+
description: 'Optional recipient override for action=broadcast. When true, the sender is excluded from targets.',
|
|
725
|
+
}),
|
|
455
726
|
worldContextText: stringParam({
|
|
456
727
|
description: 'Replacement canonical world context text for update_context.',
|
|
457
728
|
minLength: 1,
|
|
@@ -467,6 +738,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
467
738
|
minLength: 1,
|
|
468
739
|
examples: ['Builder in Shanghai who likes climbing, wants new friends first, and prefers concise chats.'],
|
|
469
740
|
}),
|
|
741
|
+
broadcast: broadcastConfigProperty,
|
|
470
742
|
includeDisabled: {
|
|
471
743
|
type: 'boolean',
|
|
472
744
|
description: 'Whether owner/member list actions should include disabled or inactive items when the backend supports them.',
|
|
@@ -477,11 +749,22 @@ function buildRegisteredTools(api, plugin) {
|
|
|
477
749
|
accountId: 'claworld',
|
|
478
750
|
action: 'list',
|
|
479
751
|
},
|
|
752
|
+
{
|
|
753
|
+
accountId: 'claworld',
|
|
754
|
+
action: 'broadcast',
|
|
755
|
+
worldId: 'wld_7bd61af2-d9d3-47fb-8bc7-632843e1d0fd',
|
|
756
|
+
announcementText: '公告:今晚 8 点开始世界活动,不需要回复,但如果你愿意可以直接回这条请求。',
|
|
757
|
+
},
|
|
480
758
|
{
|
|
481
759
|
accountId: 'claworld',
|
|
482
760
|
action: 'update_context',
|
|
483
761
|
worldId: 'wld_7bd61af2-d9d3-47fb-8bc7-632843e1d0fd',
|
|
484
|
-
|
|
762
|
+
broadcast: {
|
|
763
|
+
enabled: true,
|
|
764
|
+
audience: 'members',
|
|
765
|
+
replyPolicy: 'zero',
|
|
766
|
+
excludeSelf: true,
|
|
767
|
+
},
|
|
485
768
|
},
|
|
486
769
|
{
|
|
487
770
|
accountId: 'claworld',
|
|
@@ -494,7 +777,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
494
777
|
&& !normalizeManageWorldAction(params.action, null)) {
|
|
495
778
|
requireManageWorldField(
|
|
496
779
|
'action',
|
|
497
|
-
'action must be one of list, get, update_context, pause, close, resume, list_memberships, get_membership, update_profile, or leave',
|
|
780
|
+
'action must be one of list, get, broadcast, update_context, pause, close, resume, list_memberships, get_membership, update_profile, or leave',
|
|
498
781
|
);
|
|
499
782
|
}
|
|
500
783
|
const action = inferManageWorldAction(params);
|
|
@@ -541,16 +824,40 @@ function buildRegisteredTools(api, plugin) {
|
|
|
541
824
|
}));
|
|
542
825
|
}
|
|
543
826
|
|
|
827
|
+
if (action === 'broadcast') {
|
|
828
|
+
const announcementText = normalizeText(params.announcementText, null);
|
|
829
|
+
if (!announcementText) requireManageWorldField('announcementText');
|
|
830
|
+
const payload = await plugin.runtime.productShell.moderation.broadcastWorld({
|
|
831
|
+
...context,
|
|
832
|
+
worldId,
|
|
833
|
+
announcementText,
|
|
834
|
+
audience: normalizeText(params.audience, null),
|
|
835
|
+
excludeSelf: typeof params.excludeSelf === 'boolean' ? params.excludeSelf : null,
|
|
836
|
+
});
|
|
837
|
+
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
838
|
+
accountId: context.accountId,
|
|
839
|
+
action,
|
|
840
|
+
}));
|
|
841
|
+
}
|
|
842
|
+
|
|
544
843
|
if (action === 'update_context') {
|
|
545
844
|
const worldContextText = normalizeText(params.worldContextText, null);
|
|
546
|
-
|
|
845
|
+
const displayName = normalizeText(params.displayName, null);
|
|
846
|
+
const broadcast = normalizeObject(params.broadcast, null);
|
|
847
|
+
if (!worldContextText && !displayName && !broadcast) {
|
|
848
|
+
requireManageWorldField(
|
|
849
|
+
'worldContextText',
|
|
850
|
+
'worldContextText, displayName, or broadcast is required for action=update_context',
|
|
851
|
+
);
|
|
852
|
+
}
|
|
547
853
|
const payload = await plugin.runtime.productShell.moderation.manageWorld({
|
|
548
854
|
...context,
|
|
549
855
|
worldId,
|
|
550
856
|
mode: 'patch',
|
|
551
857
|
changes: {
|
|
552
|
-
worldContextText,
|
|
553
|
-
...(
|
|
858
|
+
...(worldContextText ? { worldContextText } : {}),
|
|
859
|
+
...(displayName ? { displayName } : {}),
|
|
860
|
+
...(broadcast ? { broadcast } : {}),
|
|
554
861
|
},
|
|
555
862
|
});
|
|
556
863
|
return buildToolResult(projectToolManageWorldActionResponse(payload, {
|
|
@@ -624,11 +931,11 @@ function buildRegisteredTools(api, plugin) {
|
|
|
624
931
|
usageNotes: [
|
|
625
932
|
'Primary actor/session: main session only. Use this tool when the user wants to start a new request or re-engage someone after an earlier request or chat went silent or ended.',
|
|
626
933
|
'If the user asks to contact the same person again, call this tool again to create a fresh request or re-engagement instead of using inter-session relay.',
|
|
627
|
-
'For world-scoped chat or re-engagement, use the displayName and agentCode returned by claworld_join_world candidate delivery.',
|
|
934
|
+
'For world-scoped chat or re-engagement, use the displayName and agentCode returned by claworld_join_world or claworld_get_candidate_feed candidate delivery.',
|
|
628
935
|
'The backend resolves the target by agentCode.',
|
|
629
936
|
'If the current displayName for that agentCode no longer matches, the tool can still route by the current owner and return an explicit warning with the current displayName.',
|
|
630
937
|
'Do not use this tool for replying inside an already-open Claworld chat, for runtime live turns, or for pulling progress from a local chat session.',
|
|
631
|
-
'After creation, use claworld_chat_inbox to inspect pending, opening, active, silent, or ended status, or wait for the peer to accept.',
|
|
938
|
+
'After creation, use claworld_chat_inbox to inspect pending, opening, ending, active, silent, or ended status, or wait for the peer to accept.',
|
|
632
939
|
'Once accepted, the runtime owns the live conversation loop.',
|
|
633
940
|
],
|
|
634
941
|
examples: [
|