@xfxstudio/claworld 0.2.9 → 0.2.10-beta.0

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 +46 -1
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +234 -3
  15. package/src/openclaw/installer/doctor.js +2 -2
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +270 -255
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +284 -79
  20. package/src/openclaw/plugin/onboarding.js +22 -42
  21. package/src/openclaw/plugin/register.js +109 -10
  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 +10 -21
  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
@@ -0,0 +1,190 @@
1
+ import {
2
+ buildPublicIdentityMissingFields,
3
+ formatPublicIdentityDisplay,
4
+ generatePublicIdentityCode,
5
+ PUBLIC_IDENTITY_STATUS,
6
+ resolvePublicIdentity,
7
+ validatePublicDisplayName,
8
+ } from '../../lib/public-identity.js';
9
+
10
+ function normalizeText(value, fallback = null) {
11
+ if (value == null) return fallback;
12
+ const normalized = String(value).trim();
13
+ return normalized || fallback;
14
+ }
15
+
16
+ function createConfigurationError() {
17
+ const error = new Error('public_identity_store_unavailable');
18
+ error.code = 'public_identity_store_unavailable';
19
+ error.status = 500;
20
+ return error;
21
+ }
22
+
23
+ function createAgentNotFoundError(agentId) {
24
+ const error = new Error(`agent_not_found:${agentId}`);
25
+ error.code = 'agent_not_found';
26
+ error.status = 404;
27
+ error.responseBody = {
28
+ error: error.code,
29
+ message: 'agent not found',
30
+ agentId: normalizeText(agentId, null),
31
+ };
32
+ return error;
33
+ }
34
+
35
+ function createInvalidPublicIdentityRequest(fieldId, message, code = 'invalid_public_identity') {
36
+ const error = new Error(code);
37
+ error.code = code;
38
+ error.status = 400;
39
+ error.responseBody = {
40
+ error: code,
41
+ message: 'public identity request is invalid',
42
+ fieldErrors: [
43
+ {
44
+ fieldId,
45
+ message,
46
+ },
47
+ ],
48
+ };
49
+ return error;
50
+ }
51
+
52
+ function createPublicIdentityIncompleteError(agent, {
53
+ capability = null,
54
+ nextTool = 'claworld_update_public_identity',
55
+ } = {}) {
56
+ const projected = projectPublicIdentityStatus(agent, { nextTool });
57
+ const capabilityLabel = normalizeText(capability, 'this Claworld capability');
58
+ const error = new Error(`public_identity_incomplete:${agent?.agentId || 'unknown'}`);
59
+ error.code = 'public_identity_incomplete';
60
+ error.status = 409;
61
+ error.responseBody = {
62
+ status: 'blocked',
63
+ error: error.code,
64
+ message: `${capabilityLabel} requires a public Claworld identity`,
65
+ agentId: normalizeText(agent?.agentId, null),
66
+ requiredAction: projected.requiredAction,
67
+ nextAction: projected.nextAction,
68
+ nextTool: projected.nextTool,
69
+ missingFields: projected.missingFields,
70
+ publicIdentity: projected.publicIdentity,
71
+ };
72
+ return error;
73
+ }
74
+
75
+ function projectPublicIdentityStatus(agent, {
76
+ nextTool = 'claworld_update_public_identity',
77
+ conversationFeedbackService = null,
78
+ } = {}) {
79
+ const publicIdentity = resolvePublicIdentity(agent);
80
+ const ready = publicIdentity.status === PUBLIC_IDENTITY_STATUS.READY;
81
+ return {
82
+ status: ready ? 'ready' : 'pending',
83
+ agentId: normalizeText(agent?.agentId, null),
84
+ ready,
85
+ publicIdentity: {
86
+ status: publicIdentity.status,
87
+ displayName: publicIdentity.displayName,
88
+ code: publicIdentity.code,
89
+ displayIdentity: formatPublicIdentityDisplay(publicIdentity),
90
+ confirmedAt: publicIdentity.confirmedAt,
91
+ updatedAt: publicIdentity.updatedAt,
92
+ },
93
+ recommendedDisplayName: normalizeText(agent?.displayName, publicIdentity.displayName || null),
94
+ nextAction: ready ? 'continue_claworld_flow' : 'set_public_identity',
95
+ requiredAction: ready ? null : 'set_public_identity',
96
+ nextTool: ready ? null : nextTool,
97
+ missingFields: ready ? [] : buildPublicIdentityMissingFields(agent),
98
+ feedbackSummary: conversationFeedbackService?.summarizeAgent?.({ agentId: agent?.agentId }) || {
99
+ totalLikesReceived: 0,
100
+ totalDislikesReceived: 0,
101
+ totalLikesGiven: 0,
102
+ totalDislikesGiven: 0,
103
+ },
104
+ };
105
+ }
106
+
107
+ export function createPublicIdentityService({ store = null, conversationFeedbackService = null } = {}) {
108
+ function assertStore() {
109
+ if (!store) throw createConfigurationError();
110
+ return store;
111
+ }
112
+
113
+ function requireAgent(agentId) {
114
+ const normalizedAgentId = normalizeText(agentId, null);
115
+ if (!normalizedAgentId) {
116
+ throw createInvalidPublicIdentityRequest('agentId', 'agentId is required');
117
+ }
118
+ const agent = assertStore().getAgent(normalizedAgentId);
119
+ if (!agent) throw createAgentNotFoundError(normalizedAgentId);
120
+ return agent;
121
+ }
122
+
123
+ function codeExists(code, excludeAgentId = null) {
124
+ return assertStore()
125
+ .listAgents()
126
+ .some((agent) => agent.agentId !== excludeAgentId && resolvePublicIdentity(agent).code === code);
127
+ }
128
+
129
+ function issueStableCode(agentId) {
130
+ for (let attempt = 0; attempt < 32; attempt += 1) {
131
+ const code = generatePublicIdentityCode();
132
+ if (!codeExists(code, agentId)) return code;
133
+ }
134
+ throw new Error('public_identity_code_generation_failed');
135
+ }
136
+
137
+ function isPublicIdentityCodeConflict(error) {
138
+ return error?.code === 'public_identity_code_conflict';
139
+ }
140
+
141
+ return {
142
+ getPublicIdentityStatus({ agentId } = {}) {
143
+ const agent = requireAgent(agentId);
144
+ return projectPublicIdentityStatus(agent, { conversationFeedbackService });
145
+ },
146
+
147
+ async updatePublicIdentity({ agentId, displayName } = {}) {
148
+ const agent = requireAgent(agentId);
149
+ const validation = validatePublicDisplayName(displayName);
150
+ if (!validation.ok) {
151
+ throw createInvalidPublicIdentityRequest('displayName', validation.message, validation.code);
152
+ }
153
+ const existingIdentity = resolvePublicIdentity(agent);
154
+ const stableCode = existingIdentity.code || null;
155
+
156
+ for (let attempt = 0; attempt < 32; attempt += 1) {
157
+ const now = assertStore().now();
158
+ const nextCode = stableCode || issueStableCode(agent.agentId);
159
+ try {
160
+ const updatedAgent = await assertStore().updateAgent(agent.agentId, {
161
+ displayName: validation.value,
162
+ publicIdentity: {
163
+ displayName: validation.value,
164
+ code: nextCode,
165
+ status: PUBLIC_IDENTITY_STATUS.READY,
166
+ confirmedAt: existingIdentity.confirmedAt || now,
167
+ updatedAt: now,
168
+ },
169
+ });
170
+ return projectPublicIdentityStatus(updatedAgent, { conversationFeedbackService });
171
+ } catch (error) {
172
+ if (!stableCode && isPublicIdentityCodeConflict(error)) {
173
+ continue;
174
+ }
175
+ throw error;
176
+ }
177
+ }
178
+
179
+ throw new Error('public_identity_code_generation_failed');
180
+ },
181
+
182
+ assertPublicIdentityReady({ agentId, capability = null } = {}) {
183
+ const agent = requireAgent(agentId);
184
+ if (resolvePublicIdentity(agent).status !== PUBLIC_IDENTITY_STATUS.READY) {
185
+ throw createPublicIdentityIncompleteError(agent, { capability });
186
+ }
187
+ return projectPublicIdentityStatus(agent, { conversationFeedbackService });
188
+ },
189
+ };
190
+ }
@@ -255,6 +255,7 @@ export function createWorldSearchService({
255
255
  worldAuthorizationService,
256
256
  store = null,
257
257
  presence = null,
258
+ conversationFeedbackService = null,
258
259
  } = {}) {
259
260
  function assertStore() {
260
261
  if (!store) throw createConfigurationError();
@@ -339,9 +340,8 @@ export function createWorldSearchService({
339
340
  playerId: candidateAgent.agentId,
340
341
  membershipId: membership.membershipId,
341
342
  worldId: world.worldId,
342
- displayName: normalizeText(candidateAgent.displayName, candidateAgent.agentCode),
343
+ displayName: normalizeText(candidateAgent.displayName, candidateAgent.agentId),
343
344
  headline: normalizeText(membership.profileSnapshot?.headline, null),
344
- address: candidateAgent.address,
345
345
  online: presenceState.online === true,
346
346
  connectedAt: presenceState.connectedAt,
347
347
  lastHeartbeatAt: presenceState.lastHeartbeatAt,
@@ -352,6 +352,13 @@ export function createWorldSearchService({
352
352
  reasonSummary: summarizeMatchedFields(matchedFields),
353
353
  joinedAt: membership.joinedAt,
354
354
  profileSummary: projectProfileSummary(world, membership.profileSnapshot || {}, candidateAgent),
355
+ worldFeedbackSummary: conversationFeedbackService?.summarizeWorldAgent?.({
356
+ worldId: world.worldId,
357
+ agentId: candidateAgent.agentId,
358
+ }) || {
359
+ likesReceived: 0,
360
+ dislikesReceived: 0,
361
+ },
355
362
  };
356
363
  })
357
364
  .filter(Boolean);
@@ -1,5 +1,6 @@
1
1
  import { normalizeAgentProfile, resolveAgentDisplayName, resolveAgentVisibility } from '../../lib/agent-profile.js';
2
2
  import { normalizeChatRequestInput } from '../../lib/chat-request.js';
3
+ import { resolvePublicIdentity } from '../../lib/public-identity.js';
3
4
  import { createKickoffBrief, resolveStoredKickoffBrief } from '../../lib/relay/kickoff-text.js';
4
5
  import { WORLD_ACTIONS } from '../worlds/world-authorization.js';
5
6
  import { normalizeChatRequestApprovalPolicy } from '../contracts/chat-request-approval-policy.js';
@@ -67,7 +68,7 @@ function createAgentNotFoundError(agentId) {
67
68
  return error;
68
69
  }
69
70
 
70
- function createTargetAddressNotFoundError(targetAgentId) {
71
+ function createTargetAgentNotFoundError(targetAgentId) {
71
72
  const error = new Error(`chat_request_target_not_found:${targetAgentId}`);
72
73
  error.code = 'chat_request_target_not_found';
73
74
  error.status = 404;
@@ -124,10 +125,8 @@ function projectAgent(store, agentId, presence = null) {
124
125
  const presenceState = presence?.getPresence?.(agent.agentId) || store.getPresence(agent.agentId);
125
126
  return {
126
127
  agentId: agent.agentId,
127
- agentCode: agent.agentCode,
128
- domain: agent.domain,
129
- address: agent.address,
130
128
  displayName: resolveAgentDisplayName(agent),
129
+ publicIdentity: resolvePublicIdentity(agent),
131
130
  profile: normalizeAgentProfile(agent.profile),
132
131
  discoverable: visibility.discoverable,
133
132
  contactable: visibility.contactable,
@@ -374,6 +373,8 @@ export function createChatRequestService({
374
373
  presence = null,
375
374
  worldService = null,
376
375
  worldAuthorizationService = null,
376
+ publicIdentityService = null,
377
+ conversationFeedbackService = null,
377
378
  } = {}) {
378
379
  function assertStore() {
379
380
  if (!store) throw createConfigurationError('chat_request_store_unavailable');
@@ -440,6 +441,15 @@ export function createChatRequestService({
440
441
  function projectChatInboxChat(conversation = {}, viewerAgentId = null, request = null) {
441
442
  const direction = resolveInboxChatDirection(viewerAgentId, request);
442
443
  const counterpartyAgentId = resolveInboxChatCounterpartyAgentId(viewerAgentId, request, conversation);
444
+ const feedbackSummary = conversationFeedbackService?.summarizeConversation?.({
445
+ conversationKey: conversation.conversationKey,
446
+ viewerAgentId,
447
+ }) || {
448
+ likeCount: 0,
449
+ dislikeCount: 0,
450
+ viewerGave: null,
451
+ viewerReceived: null,
452
+ };
443
453
 
444
454
  return {
445
455
  chatRequestId: normalizeText(request?.chatRequestId || request?.requestId, null),
@@ -452,6 +462,7 @@ export function createChatRequestService({
452
462
  localSessionKey: normalizeText(conversation.sessionKey, null),
453
463
  counterparty: projectAgent(assertStore(), counterpartyAgentId, presence),
454
464
  conversation: resolveInboxConversationWorldSummary(worldService, request, conversation),
465
+ feedbackSummary,
455
466
  };
456
467
  }
457
468
 
@@ -501,6 +512,10 @@ export function createChatRequestService({
501
512
  source = 'chat_request',
502
513
  } = {}) {
503
514
  requireAgent(fromAgentId);
515
+ publicIdentityService?.assertPublicIdentityReady?.({
516
+ agentId: fromAgentId,
517
+ capability: 'request chat',
518
+ });
504
519
  const normalizedTargetAgentId = normalizeText(targetAgentId, null);
505
520
  if (!normalizedTargetAgentId) {
506
521
  throw createInvalidChatRequestError('chat_request_target_required', 'chat request target requires targetAgentId');
@@ -513,8 +528,8 @@ export function createChatRequestService({
513
528
  });
514
529
  const normalizedWorldId = normalizeConversationWorldId(worldId)
515
530
  || normalizeConversationWorldId(normalizedRequestInput.conversation?.worldId);
516
- if (!targetAgent?.address) {
517
- throw createTargetAddressNotFoundError(normalizedTargetAgentId);
531
+ if (!targetAgent?.agentId) {
532
+ throw createTargetAgentNotFoundError(normalizedTargetAgentId);
518
533
  }
519
534
  const normalizedOpeningPayload = cloneJsonObject(openingPayload) || cloneJsonObject(normalizedRequestInput.openingPayload);
520
535
  const normalizedKickoffBrief = createKickoffBrief({
@@ -549,7 +564,7 @@ export function createChatRequestService({
549
564
 
550
565
  const result = await assertRelay('createChatRequest').createChatRequest({
551
566
  fromAgentId,
552
- toAddress: targetAgent.address,
567
+ targetAgentId: targetAgent.agentId,
553
568
  kickoffBrief: normalizedKickoffBrief,
554
569
  openingMessage: normalizeText(
555
570
  normalizedKickoffBrief?.text,
@@ -12,7 +12,7 @@ export function registerFriendRoutes(app, { friendService }) {
12
12
  try {
13
13
  const result = await friendService.createFriendRequest({
14
14
  fromAgentId: req.body?.fromAgentId,
15
- toAddress: req.body?.toAddress,
15
+ targetAgentId: req.body?.targetAgentId,
16
16
  message: req.body?.message,
17
17
  metadata: req.body?.metadata,
18
18
  });
@@ -1,16 +1,12 @@
1
1
  import { normalizeAgentProfile, resolveAgentDisplayName, resolveAgentVisibility } from '../../lib/agent-profile.js';
2
2
  import { createRelayPolicyHooks, evaluatePolicyHook } from '../../lib/policy.js';
3
+ import { resolvePublicIdentity } from '../../lib/public-identity.js';
3
4
 
4
5
  function normalizeAgentId(agentId) {
5
6
  const normalized = String(agentId || '').trim();
6
7
  return normalized || null;
7
8
  }
8
9
 
9
- function normalizeAddress(address) {
10
- const normalized = String(address || '').trim().toLowerCase();
11
- return normalized || null;
12
- }
13
-
14
10
  function normalizeDirection(direction) {
15
11
  const normalized = String(direction || '').trim().toLowerCase();
16
12
  return normalized === 'inbound' || normalized === 'outbound' ? normalized : null;
@@ -54,8 +50,8 @@ function createAgentNotFoundError(agentId) {
54
50
  return error;
55
51
  }
56
52
 
57
- function createTargetNotFoundError(address) {
58
- const error = new Error(`friend_target_not_found:${address}`);
53
+ function createTargetNotFoundError(targetAgentId) {
54
+ const error = new Error(`friend_target_not_found:${targetAgentId}`);
59
55
  error.code = 'friend_target_not_found';
60
56
  error.status = 404;
61
57
  return error;
@@ -131,10 +127,8 @@ function projectAgent(store, agentId) {
131
127
  const visibility = resolveAgentVisibility(agent);
132
128
  return {
133
129
  agentId: agent.agentId,
134
- agentCode: agent.agentCode,
135
- domain: agent.domain,
136
- address: agent.address,
137
130
  displayName: resolveAgentDisplayName(agent),
131
+ publicIdentity: resolvePublicIdentity(agent),
138
132
  profile: normalizeAgentProfile(agent.profile),
139
133
  discoverable: visibility.discoverable,
140
134
  contactable: visibility.contactable,
@@ -149,7 +143,7 @@ function resolvePeerAgentId(friendship, viewerAgentId) {
149
143
  return null;
150
144
  }
151
145
 
152
- export function createFriendService({ store = null, policy = null } = {}) {
146
+ export function createFriendService({ store = null, policy = null, publicIdentityService = null } = {}) {
153
147
  const relayPolicy = createRelayPolicyHooks(policy);
154
148
 
155
149
  function assertStore() {
@@ -307,23 +301,27 @@ export function createFriendService({ store = null, policy = null } = {}) {
307
301
  }
308
302
 
309
303
  return {
310
- async createFriendRequest({ fromAgentId, toAddress, message = null, metadata = {} } = {}) {
304
+ async createFriendRequest({ fromAgentId, targetAgentId, message = null, metadata = {} } = {}) {
311
305
  const friendshipStore = assertStore();
312
306
  const fromAgent = requireAgent(fromAgentId);
313
- const normalizedToAddress = normalizeAddress(toAddress);
314
- if (!normalizedToAddress) {
315
- throw createTargetNotFoundError(toAddress);
307
+ publicIdentityService?.assertPublicIdentityReady?.({
308
+ agentId: fromAgent.agentId,
309
+ capability: 'send friend request',
310
+ });
311
+ const normalizedTargetAgentId = normalizeAgentId(targetAgentId);
312
+ if (!normalizedTargetAgentId) {
313
+ throw createTargetNotFoundError(targetAgentId);
316
314
  }
317
315
 
318
- const toAgent = friendshipStore.resolveAddress(normalizedToAddress);
319
- if (!toAgent) throw createTargetNotFoundError(normalizedToAddress);
316
+ const toAgent = friendshipStore.getAgent(normalizedTargetAgentId);
317
+ if (!toAgent) throw createTargetNotFoundError(normalizedTargetAgentId);
320
318
 
321
319
  const canRequest = evaluatePolicyHook({
322
320
  hook: relayPolicy.canRequest,
323
321
  context: {
324
322
  fromAgentId: fromAgent.agentId,
325
323
  fromAgent,
326
- toAddress: normalizedToAddress,
324
+ targetAgentId: normalizedTargetAgentId,
327
325
  toAgent,
328
326
  requestContext: {
329
327
  type: 'friend_request',
@@ -382,7 +380,6 @@ export function createFriendService({ store = null, policy = null } = {}) {
382
380
  const request = await friendshipStore.createFriendRequest({
383
381
  fromAgentId: fromAgent.agentId,
384
382
  toAgentId: toAgent.agentId,
385
- toAddress: toAgent.address,
386
383
  message: normalizeMessage(message),
387
384
  metadata,
388
385
  });
@@ -10,8 +10,8 @@ function sendSocialError(res, error) {
10
10
  export function registerSocialRoutes(app, { socialService }) {
11
11
  app.get('/v1/social/agents/lookup', (req, res) => {
12
12
  try {
13
- const result = socialService.lookupAgentByCode({
14
- agentCode: req.query.agentCode,
13
+ const result = socialService.lookupAgentByIdentity({
14
+ identity: req.query.identity,
15
15
  });
16
16
  res.json(result);
17
17
  } catch (error) {
@@ -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,