@xfxstudio/claworld 0.2.9 → 0.2.10-beta.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.
Files changed (49) hide show
  1. package/README.md +1 -1
  2. package/openclaw.plugin.json +7 -63
  3. package/package.json +6 -2
  4. package/skills/claworld-help/SKILL.md +5 -1
  5. package/skills/claworld-join-and-chat/SKILL.md +21 -1
  6. package/skills/claworld-manage-worlds/SKILL.md +81 -10
  7. package/src/lib/agent-profile.js +8 -3
  8. package/src/lib/chat-request.js +0 -1
  9. package/src/lib/policy.js +2 -6
  10. package/src/lib/public-identity.js +175 -0
  11. package/src/lib/relay/kickoff-text.js +1 -0
  12. package/src/openclaw/installer/cli.js +48 -4
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +247 -71
  15. package/src/openclaw/installer/doctor.js +31 -17
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +453 -263
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +294 -84
  20. package/src/openclaw/plugin/onboarding.js +37 -45
  21. package/src/openclaw/plugin/register.js +124 -13
  22. package/src/openclaw/plugin/relay-client.js +233 -17
  23. package/src/openclaw/runtime/backend-error-context.js +91 -0
  24. package/src/openclaw/runtime/feedback-helper.js +1 -2
  25. package/src/openclaw/runtime/product-shell-helper.js +43 -9
  26. package/src/openclaw/runtime/tool-contracts.js +26 -3
  27. package/src/openclaw/runtime/tool-inventory.js +7 -0
  28. package/src/openclaw/runtime/world-moderation-helper.js +3 -19
  29. package/src/product-shell/contracts/candidate-feed.js +7 -0
  30. package/src/product-shell/contracts/world-manifest.js +0 -1
  31. package/src/product-shell/contracts/world-orchestration.js +10 -1
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +261 -0
  33. package/src/product-shell/feedback/feedback-routes.js +0 -1
  34. package/src/product-shell/feedback/feedback-service.js +4 -9
  35. package/src/product-shell/index.js +40 -7
  36. package/src/product-shell/matching/matchmaking-service.js +22 -1
  37. package/src/product-shell/membership/membership-service.js +5 -1
  38. package/src/product-shell/onboarding/onboarding-service.js +16 -26
  39. package/src/product-shell/profile/public-identity-routes.js +60 -0
  40. package/src/product-shell/profile/public-identity-service.js +190 -0
  41. package/src/product-shell/search/search-service.js +9 -2
  42. package/src/product-shell/social/chat-request-service.js +22 -7
  43. package/src/product-shell/social/friend-routes.js +1 -1
  44. package/src/product-shell/social/friend-service.js +16 -19
  45. package/src/product-shell/social/social-routes.js +2 -2
  46. package/src/product-shell/social/social-service.js +31 -35
  47. package/src/product-shell/worlds/world-admin-service.js +31 -10
  48. package/src/product-shell/worlds/world-broadcast-service.js +2 -2
  49. package/src/lib/agent-address.js +0 -46
@@ -3,7 +3,7 @@ import {
3
3
  resolveAgentDisplayName,
4
4
  resolveAgentVisibility,
5
5
  } from '../../lib/agent-profile.js';
6
- import { parseAgentHandle } from '../../lib/agent-address.js';
6
+ import { parsePublicIdentityDisplay, resolvePublicIdentity } from '../../lib/public-identity.js';
7
7
 
8
8
  function normalizeText(value, fallback = null) {
9
9
  if (value == null) return fallback;
@@ -11,18 +11,6 @@ function normalizeText(value, fallback = null) {
11
11
  return normalized || fallback;
12
12
  }
13
13
 
14
- function parseCanonicalAgentCode(value) {
15
- const parsed = parseAgentHandle(value);
16
- if (!parsed?.canonical) return null;
17
-
18
- return {
19
- agentCode: parsed.address,
20
- relayLocalCode: parsed.localPart,
21
- domain: parsed.domain,
22
- address: parsed.address,
23
- };
24
- }
25
-
26
14
  function createConfigurationError() {
27
15
  const error = new Error('social_lookup_store_unavailable');
28
16
  error.code = 'social_lookup_store_unavailable';
@@ -30,44 +18,44 @@ function createConfigurationError() {
30
18
  return error;
31
19
  }
32
20
 
33
- function createInvalidAgentCodeError(agentCode) {
34
- const error = new Error('invalid_agent_code');
35
- error.code = 'invalid_agent_code';
21
+ function createInvalidPublicIdentityError(identity) {
22
+ const error = new Error('invalid_public_identity');
23
+ error.code = 'invalid_public_identity';
36
24
  error.status = 400;
37
25
  error.responseBody = {
38
26
  error: error.code,
39
- message: 'agentCode must use canonical local@namespace schema',
40
- agentCode: normalizeText(agentCode, null),
27
+ message: 'identity must use displayName#code',
28
+ identity: normalizeText(identity, null),
41
29
  fieldErrors: [
42
30
  {
43
- fieldId: 'agentCode',
44
- message: 'agentCode must use canonical local@namespace schema',
31
+ fieldId: 'identity',
32
+ message: 'identity must use displayName#code',
45
33
  },
46
34
  ],
47
35
  };
48
36
  return error;
49
37
  }
50
38
 
51
- function createAgentNotFoundError(agentCode) {
52
- const error = new Error(`agent_not_found:${agentCode}`);
39
+ function createAgentNotFoundError(identity) {
40
+ const error = new Error(`agent_not_found:${identity}`);
53
41
  error.code = 'agent_not_found';
54
42
  error.status = 404;
55
43
  error.responseBody = {
56
44
  error: error.code,
57
- message: 'no agent found for canonical agentCode',
58
- agentCode,
45
+ message: 'no agent found for public identity',
46
+ identity,
59
47
  };
60
48
  return error;
61
49
  }
62
50
 
63
- function createNotDiscoverableError(agentCode) {
64
- const error = new Error(`not_discoverable:${agentCode}`);
51
+ function createNotDiscoverableError(identity) {
52
+ const error = new Error(`not_discoverable:${identity}`);
65
53
  error.code = 'not_discoverable';
66
54
  error.status = 403;
67
55
  error.responseBody = {
68
56
  error: error.code,
69
57
  message: 'agent is not discoverable',
70
- agentCode,
58
+ identity,
71
59
  };
72
60
  return error;
73
61
  }
@@ -94,21 +82,27 @@ export function createSocialService({ worldService, store = null } = {}) {
94
82
  }
95
83
 
96
84
  return {
97
- lookupAgentByCode({ agentCode } = {}) {
85
+ lookupAgentByIdentity({ identity } = {}) {
98
86
  const socialStore = assertStore();
99
- const parsedAgentCode = parseCanonicalAgentCode(agentCode);
100
- if (!parsedAgentCode) {
101
- throw createInvalidAgentCodeError(agentCode);
87
+ const parsedIdentity = parsePublicIdentityDisplay(identity);
88
+ if (!parsedIdentity) {
89
+ throw createInvalidPublicIdentityError(identity);
102
90
  }
103
91
 
104
- const agent = socialStore.resolveAddress(parsedAgentCode.address);
92
+ const agent = socialStore
93
+ .listAgents()
94
+ .find((candidate) => {
95
+ const candidateIdentity = resolvePublicIdentity(candidate);
96
+ return candidateIdentity.status === 'ready'
97
+ && candidateIdentity.code === parsedIdentity.code;
98
+ }) || null;
105
99
  if (!agent) {
106
- throw createAgentNotFoundError(parsedAgentCode.agentCode);
100
+ throw createAgentNotFoundError(parsedIdentity.identity);
107
101
  }
108
102
 
109
103
  const visibility = resolveAgentVisibility(agent);
110
104
  if (!visibility.discoverable) {
111
- throw createNotDiscoverableError(parsedAgentCode.agentCode);
105
+ throw createNotDiscoverableError(parsedIdentity.identity);
112
106
  }
113
107
 
114
108
  const activeWorlds = socialStore
@@ -124,8 +118,10 @@ export function createSocialService({ worldService, store = null } = {}) {
124
118
  return {
125
119
  status: 'found',
126
120
  publicProfile: {
127
- agentCode: agent.address || parsedAgentCode.agentCode,
121
+ agentId: agent.agentId,
122
+ identity: resolvePublicIdentity(agent).displayIdentity || parsedIdentity.identity,
128
123
  displayName: resolveAgentDisplayName(agent),
124
+ code: resolvePublicIdentity(agent).code,
129
125
  profile: normalizeAgentProfile(agent.profile),
130
126
  discoverable: visibility.discoverable,
131
127
  contactable: visibility.contactable,
@@ -180,7 +180,7 @@ function buildWorldRecord({
180
180
  displayName,
181
181
  summary,
182
182
  worldContextText = null,
183
- enabled = false,
183
+ enabled = true,
184
184
  status = null,
185
185
  existingMetrics = null,
186
186
  } = {}) {
@@ -246,17 +246,23 @@ function projectParticipantContextField(world = {}) {
246
246
  };
247
247
  }
248
248
 
249
- function projectWorldStats(store, world = {}) {
249
+ function projectWorldStats(store, world = {}, conversationFeedbackService = null) {
250
250
  const totalParticipants = store.countMemberships({ worldId: world.worldId });
251
251
  const activeParticipants = store.countMemberships({ worldId: world.worldId, status: 'active' });
252
+ const feedbackSummary = conversationFeedbackService?.summarizeWorld?.({ worldId: world.worldId }) || {
253
+ totalLikes: 0,
254
+ totalDislikes: 0,
255
+ };
252
256
  return {
253
257
  totalParticipants,
254
258
  activeParticipants,
255
259
  totalConversationCount: Number(world.metrics?.totalConversationCount || 0),
260
+ totalLikes: feedbackSummary.totalLikes,
261
+ totalDislikes: feedbackSummary.totalDislikes,
256
262
  };
257
263
  }
258
264
 
259
- function projectManagedWorldSummary(store, world = {}, { worldRole = null } = {}) {
265
+ function projectManagedWorldSummary(store, world = {}, { worldRole = null, conversationFeedbackService = null } = {}) {
260
266
  return {
261
267
  worldId: world.worldId,
262
268
  displayName: world.displayName,
@@ -267,11 +273,11 @@ function projectManagedWorldSummary(store, world = {}, { worldRole = null } = {}
267
273
  worldRole: normalizeWorldRole(worldRole, null),
268
274
  createdAt: world.createdAt || null,
269
275
  updatedAt: world.updatedAt || null,
270
- stats: projectWorldStats(store, world),
276
+ stats: projectWorldStats(store, world, conversationFeedbackService),
271
277
  };
272
278
  }
273
279
 
274
- function projectManagedWorld(store, world = {}, { worldRole = null } = {}) {
280
+ function projectManagedWorld(store, world = {}, { worldRole = null, conversationFeedbackService = null } = {}) {
275
281
  return {
276
282
  worldId: world.worldId,
277
283
  displayName: world.displayName,
@@ -284,7 +290,7 @@ function projectManagedWorld(store, world = {}, { worldRole = null } = {}) {
284
290
  createdAt: world.createdAt || null,
285
291
  updatedAt: world.updatedAt || null,
286
292
  participantContextField: projectParticipantContextField(world),
287
- stats: projectWorldStats(store, world),
293
+ stats: projectWorldStats(store, world, conversationFeedbackService),
288
294
  };
289
295
  }
290
296
 
@@ -299,7 +305,13 @@ function buildWorldId(displayName, existingIds = []) {
299
305
  return `${base}-${counter}`;
300
306
  }
301
307
 
302
- export function createWorldAdminService({ worldService, worldAuthorizationService, store = null } = {}) {
308
+ export function createWorldAdminService({
309
+ worldService,
310
+ worldAuthorizationService,
311
+ store = null,
312
+ publicIdentityService = null,
313
+ conversationFeedbackService = null,
314
+ } = {}) {
303
315
  function assertStore() {
304
316
  if (!store) throw createConfigurationError();
305
317
  return store;
@@ -343,11 +355,15 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
343
355
  creatorAgentId,
344
356
  displayName,
345
357
  worldContextText,
346
- enabled = false,
358
+ enabled = true,
347
359
  status = null,
348
360
  } = {}) {
349
361
  const storeBacked = assertStore();
350
362
  const resolvedOwnerAgentId = assertActorAgent(ownerAgentId || creatorAgentId);
363
+ publicIdentityService?.assertPublicIdentityReady?.({
364
+ agentId: resolvedOwnerAgentId,
365
+ capability: 'create world',
366
+ });
351
367
  const resolvedDisplayName = normalizeText(displayName, null);
352
368
  if (!resolvedDisplayName) throw createInvalidWorldRequestError('displayName');
353
369
  const resolvedWorldContextText = normalizeText(worldContextText, null);
@@ -360,8 +376,8 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
360
376
  displayName: resolvedDisplayName,
361
377
  summary: summarizeWorldContextText(resolvedWorldContextText, resolvedDisplayName),
362
378
  worldContextText: resolvedWorldContextText,
363
- enabled: normalizeBoolean(enabled, false),
364
- status: normalizeOwnerWorldStatus(status, normalizeBoolean(enabled, false) ? 'enabled' : 'draft'),
379
+ enabled: normalizeBoolean(enabled, true),
380
+ status: normalizeOwnerWorldStatus(status, normalizeBoolean(enabled, true) ? 'enabled' : 'draft'),
365
381
  });
366
382
 
367
383
  const created = await storeBacked.createWorldConfig(worldRecord);
@@ -369,6 +385,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
369
385
 
370
386
  return projectManagedWorld(storeBacked, normalizedWorld, {
371
387
  worldRole: WORLD_ROLES.OWNER,
388
+ conversationFeedbackService,
372
389
  });
373
390
  },
374
391
  listManagedWorlds({ actorAgentId, creatorAgentId, includeDisabled = true } = {}) {
@@ -383,6 +400,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
383
400
  }))
384
401
  .map((context) => projectManagedWorldSummary(storeBacked, context.world, {
385
402
  worldRole: context.worldRole,
403
+ conversationFeedbackService,
386
404
  }));
387
405
  },
388
406
  listOwnedWorlds(input = {}) {
@@ -397,6 +415,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
397
415
  });
398
416
  return projectManagedWorld(storeBacked, authorization.world, {
399
417
  worldRole: authorization.worldRole,
418
+ conversationFeedbackService,
400
419
  });
401
420
  },
402
421
  async manageWorld({ actorAgentId, creatorAgentId, worldId, changes = null, enabled = null, status = null } = {}) {
@@ -417,6 +436,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
417
436
  if (!hasChanges && resolvedEnabled == null && normalizedStatus == null) {
418
437
  return projectManagedWorld(storeBacked, existingWorld, {
419
438
  worldRole: authorization.worldRole,
439
+ conversationFeedbackService,
420
440
  });
421
441
  }
422
442
 
@@ -459,6 +479,7 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
459
479
  const normalizedWorld = worldService.requireWorld(updated.worldId, { includeDisabled: true });
460
480
  return projectManagedWorld(storeBacked, normalizedWorld, {
461
481
  worldRole: authorization.worldRole,
482
+ conversationFeedbackService,
462
483
  });
463
484
  },
464
485
  };
@@ -213,14 +213,14 @@ export function createWorldBroadcastService({
213
213
  const failures = [];
214
214
  for (const targetAgentId of targetAgentIds) {
215
215
  const targetAgent = store.getAgent(targetAgentId);
216
- if (!targetAgent?.address) {
216
+ if (!targetAgent?.agentId) {
217
217
  failures.push({
218
218
  agentId: targetAgentId,
219
219
  status: 'failed',
220
220
  httpStatus: 404,
221
221
  error: 'target_not_found',
222
222
  reason: 'target_not_found',
223
- message: 'target agent is missing a relay address',
223
+ message: 'target agent was not found',
224
224
  });
225
225
  continue;
226
226
  }
@@ -1,46 +0,0 @@
1
- const AGENT_HANDLE_SEGMENT_PATTERN = /^[A-Za-z0-9._:+~-]+$/i;
2
-
3
- function normalizeSegment(value) {
4
- const normalized = String(value || '').trim().toLowerCase();
5
- return normalized || null;
6
- }
7
-
8
- export function isValidAgentHandleSegment(value) {
9
- const normalized = normalizeSegment(value);
10
- return Boolean(normalized && AGENT_HANDLE_SEGMENT_PATTERN.test(normalized));
11
- }
12
-
13
- export function parseAgentHandle(value, { defaultDomain = null } = {}) {
14
- const normalizedValue = String(value || '').trim().toLowerCase();
15
- if (!normalizedValue) return null;
16
-
17
- const firstAtIndex = normalizedValue.indexOf('@');
18
- if (firstAtIndex === -1) {
19
- const normalizedDomain = normalizeSegment(defaultDomain);
20
- if (!isValidAgentHandleSegment(normalizedValue) || !isValidAgentHandleSegment(normalizedDomain)) {
21
- return null;
22
- }
23
- return {
24
- localPart: normalizedValue,
25
- domain: normalizedDomain,
26
- address: `${normalizedValue}@${normalizedDomain}`,
27
- canonical: false,
28
- };
29
- }
30
-
31
- if (firstAtIndex === 0 || firstAtIndex === normalizedValue.length - 1) return null;
32
- if (normalizedValue.indexOf('@', firstAtIndex + 1) !== -1) return null;
33
-
34
- const localPart = normalizeSegment(normalizedValue.slice(0, firstAtIndex));
35
- const domain = normalizeSegment(normalizedValue.slice(firstAtIndex + 1));
36
- if (!isValidAgentHandleSegment(localPart) || !isValidAgentHandleSegment(domain)) {
37
- return null;
38
- }
39
-
40
- return {
41
- localPart,
42
- domain,
43
- address: `${localPart}@${domain}`,
44
- canonical: true,
45
- };
46
- }