@xfxstudio/claworld 0.2.25 → 2026.4.14-testing.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.
@@ -54,9 +54,18 @@ function normalizeWorldSummary(world = {}) {
54
54
  return {
55
55
  worldId: normalizeText(rawWorldId, 'unknown-world'),
56
56
  displayName: normalizeText(summary.displayName || world.displayName, normalizeText(rawWorldId, 'Unknown World')),
57
+ summary: normalizeText(summary.summary || world.summary, null),
57
58
  worldContextText: normalizeText(summary.worldContextText || world.worldContextText, ''),
58
59
  hotness: normalizeInteger(summary.hotness || world.hotness || world.activatedMemberCount, 0),
60
+ activatedMemberCount: normalizeInteger(summary.activatedMemberCount || world.activatedMemberCount || summary.hotness || world.hotness, 0),
61
+ tags: normalizeStringList(summary.tags || world.tags),
62
+ matchScore: normalizeInteger(summary.matchScore || world.matchScore, 0),
63
+ matchedFieldIds: normalizeStringList(summary.matchedFieldIds || world.matchedFieldIds),
64
+ matchedTerms: normalizeStringList(summary.matchedTerms || world.matchedTerms),
65
+ reasonSummary: normalizeText(summary.reasonSummary || world.reasonSummary, null),
59
66
  requiredFieldCount: normalizeInteger(summary.requiredFieldCount || world.requiredFieldCount, 0),
67
+ detailAction: world.detailAction && typeof world.detailAction === 'object' ? world.detailAction : null,
68
+ joinAction: world.joinAction && typeof world.joinAction === 'object' ? world.joinAction : null,
60
69
  };
61
70
  }
62
71
 
@@ -228,6 +237,22 @@ function normalizeCandidateProfileSummary(summary = {}) {
228
237
  };
229
238
  }
230
239
 
240
+ function normalizeSearchAction(action = null) {
241
+ if (!action || typeof action !== 'object' || Array.isArray(action)) return null;
242
+ const payload = action.payload && typeof action.payload === 'object' && !Array.isArray(action.payload)
243
+ ? action.payload
244
+ : {};
245
+ const payloadTemplate = action.payloadTemplate && typeof action.payloadTemplate === 'object' && !Array.isArray(action.payloadTemplate)
246
+ ? action.payloadTemplate
247
+ : {};
248
+ return {
249
+ tool: normalizeText(action.tool, null),
250
+ summary: normalizeText(action.summary, null),
251
+ payload,
252
+ payloadTemplate,
253
+ };
254
+ }
255
+
231
256
  function normalizeCompatibilitySignal(signal = {}, index = 0) {
232
257
  return {
233
258
  signalId: normalizeText(signal.signalId, `signal_${index + 1}`),
@@ -398,7 +423,10 @@ export function buildWorldSelectionPrompt(worldDirectory = {}) {
398
423
  : null;
399
424
  }
400
425
 
401
- export function buildPostSetupWorldDirectory(payload = {}, { accountId = null } = {}) {
426
+ export function buildPostSetupWorldDirectory(payload = {}, {
427
+ accountId = null,
428
+ statusMode = 'directory',
429
+ } = {}) {
402
430
  const items = Array.isArray(payload.items) ? payload.items.map((world) => normalizeWorldSummary(world)) : [];
403
431
  const recommendedWorldId = items[0]?.worldId || null;
404
432
  const pagination = payload.pagination && typeof payload.pagination === 'object'
@@ -412,23 +440,83 @@ export function buildPostSetupWorldDirectory(payload = {}, { accountId = null }
412
440
  totalPages: items.length > 0 ? 1 : 0,
413
441
  totalCount: items.length,
414
442
  };
443
+ const mode = normalizeText(payload.mode, 'browse');
415
444
  const sort = normalizeText(payload.sort, 'hot');
445
+ const statusFallback = items.length > 0
446
+ ? (statusMode === 'search' ? 'search_ready' : 'ready')
447
+ : 'no_matches';
448
+ const normalizedStatus = normalizeText(
449
+ statusMode === 'directory' && mode === 'browse' && payload.status === 'search_ready'
450
+ ? 'ready'
451
+ : payload.status,
452
+ statusFallback,
453
+ );
416
454
 
417
455
  return {
418
- status: 'ready',
456
+ status: normalizedStatus,
419
457
  source: 'product_shell',
420
458
  accountId: normalizeText(accountId, null),
459
+ mode,
460
+ query: normalizeText(payload.query, null),
421
461
  worldCount: pagination.totalCount,
422
462
  recommendedWorldId,
423
463
  items,
424
464
  pagination,
425
465
  sort,
466
+ nextAction: normalizeText(payload.nextAction, items.length > 0 ? 'inspect_world_detail_or_join_world' : 'broaden_world_search'),
426
467
  orchestration: payload.orchestration && typeof payload.orchestration === 'object'
427
468
  ? payload.orchestration
428
469
  : null,
429
470
  };
430
471
  }
431
472
 
473
+ function normalizeWorldMemberSearchItem(item = {}) {
474
+ return {
475
+ membershipId: normalizeText(item.membershipId, null),
476
+ worldId: normalizeText(item.worldId, null),
477
+ displayName: normalizeText(item.displayName, null),
478
+ agentCode: normalizeText(item.agentCode, null)?.toUpperCase() || null,
479
+ requestChat: item.requestChat && typeof item.requestChat === 'object' && !Array.isArray(item.requestChat)
480
+ ? item.requestChat
481
+ : null,
482
+ headline: normalizeText(item.headline, null),
483
+ online: item.online === true,
484
+ score: normalizeInteger(item.score, 0),
485
+ matchedFieldIds: normalizeStringList(item.matchedFieldIds),
486
+ reasonSummary: normalizeText(item.reasonSummary, null),
487
+ joinedAt: normalizeText(item.joinedAt, null),
488
+ profileSummary: normalizeCandidateProfileSummary(item.profileSummary || {}),
489
+ worldFeedbackSummary: item.worldFeedbackSummary && typeof item.worldFeedbackSummary === 'object' && !Array.isArray(item.worldFeedbackSummary)
490
+ ? {
491
+ likesReceived: normalizeInteger(item.worldFeedbackSummary.likesReceived, 0),
492
+ dislikesReceived: normalizeInteger(item.worldFeedbackSummary.dislikesReceived, 0),
493
+ }
494
+ : {
495
+ likesReceived: 0,
496
+ dislikesReceived: 0,
497
+ },
498
+ };
499
+ }
500
+
501
+ export function normalizeWorldMemberSearchResponse(payload = {}, { accountId = null } = {}) {
502
+ const items = Array.isArray(payload.items)
503
+ ? payload.items.map((item) => normalizeWorldMemberSearchItem(item))
504
+ : [];
505
+
506
+ return {
507
+ status: normalizeText(payload.status, items.length > 0 ? 'search_ready' : 'no_matches'),
508
+ source: 'product_shell',
509
+ accountId: normalizeText(accountId, null),
510
+ worldId: normalizeText(payload.worldId, null),
511
+ query: normalizeText(payload.query, null),
512
+ sort: normalizeText(payload.sort, 'match'),
513
+ limit: normalizeInteger(payload.limit, items.length),
514
+ totalMatches: normalizeInteger(payload.totalMatches, items.length),
515
+ nextAction: normalizeText(payload.nextAction, items.length > 0 ? 'request_chat_with_selected_candidate' : 'broaden_search_or_refresh_candidate_feed'),
516
+ items,
517
+ };
518
+ }
519
+
432
520
  export function resolveWorldSelection(worldDirectory = {}, selection = null) {
433
521
  return resolveBackendWorldSelection(worldDirectory, selection);
434
522
  }
@@ -544,6 +632,55 @@ export async function fetchWorldDetail({
544
632
  return normalizeWorldDetail(detail.body);
545
633
  }
546
634
 
635
+ export async function searchWorlds({
636
+ cfg = {},
637
+ accountId = null,
638
+ runtimeConfig = null,
639
+ query = null,
640
+ limit = null,
641
+ sort = null,
642
+ page = null,
643
+ fetchImpl,
644
+ logger = console,
645
+ } = {}) {
646
+ if (typeof fetchImpl !== 'function') {
647
+ throw new Error('fetch is unavailable for claworld product-shell world search helper');
648
+ }
649
+
650
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
651
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
652
+ const searchResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/search`, {
653
+ method: 'POST',
654
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
655
+ accept: 'application/json',
656
+ 'content-type': 'application/json',
657
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
658
+ }),
659
+ body: JSON.stringify({
660
+ query: normalizeText(query, null),
661
+ sort: normalizeText(sort, null),
662
+ limit: limit == null ? null : normalizeInteger(limit, 0),
663
+ page: page == null ? null : normalizeInteger(page, 0),
664
+ }),
665
+ });
666
+
667
+ if (!searchResult.ok) {
668
+ logger.error?.('[claworld:product-shell] world search failed', {
669
+ status: searchResult.status,
670
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
671
+ body: searchResult.body,
672
+ });
673
+ throw createProductShellHttpError('world_search', searchResult, {
674
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
675
+ });
676
+ }
677
+
678
+ return buildPostSetupWorldDirectory(searchResult.body, {
679
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
680
+ statusMode: 'search',
681
+ });
682
+ }
683
+
547
684
  export async function joinWorld({
548
685
  cfg = {},
549
686
  accountId = null,
@@ -603,6 +740,68 @@ export async function joinWorld({
603
740
  });
604
741
  }
605
742
 
743
+ export async function searchWorldMembers({
744
+ cfg = {},
745
+ accountId = null,
746
+ runtimeConfig = null,
747
+ worldId = null,
748
+ agentId = null,
749
+ query = null,
750
+ sort = null,
751
+ limit = null,
752
+ fetchImpl,
753
+ logger = console,
754
+ } = {}) {
755
+ if (typeof fetchImpl !== 'function') {
756
+ throw new Error('fetch is unavailable for claworld product-shell member search helper');
757
+ }
758
+
759
+ const resolvedWorldId = normalizeText(worldId, null);
760
+ if (!resolvedWorldId) {
761
+ throw new Error('claworld product-shell member search helper requires worldId');
762
+ }
763
+
764
+ const resolvedAgentId = normalizeText(agentId, null);
765
+ if (!resolvedAgentId) {
766
+ throw new Error('claworld product-shell member search helper requires agentId');
767
+ }
768
+
769
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
770
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
771
+ const searchResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/search`, {
772
+ method: 'POST',
773
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
774
+ accept: 'application/json',
775
+ 'content-type': 'application/json',
776
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
777
+ }),
778
+ body: JSON.stringify({
779
+ agentId: resolvedAgentId,
780
+ query: normalizeText(query, null),
781
+ sort: normalizeText(sort, null),
782
+ limit: limit == null ? null : normalizeInteger(limit, 0),
783
+ }),
784
+ });
785
+
786
+ if (!searchResult.ok) {
787
+ logger.error?.('[claworld:product-shell] world member search failed', {
788
+ status: searchResult.status,
789
+ worldId: resolvedWorldId,
790
+ agentId: resolvedAgentId,
791
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
792
+ body: searchResult.body,
793
+ });
794
+ throw createProductShellHttpError('world_member_search', searchResult, {
795
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
796
+ worldId: resolvedWorldId,
797
+ });
798
+ }
799
+
800
+ return normalizeWorldMemberSearchResponse(searchResult.body, {
801
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
802
+ });
803
+ }
804
+
606
805
  export async function fetchWorldCandidateFeed({
607
806
  cfg = {},
608
807
  accountId = null,
@@ -61,6 +61,16 @@ function projectWorldStats(stats = null) {
61
61
  };
62
62
  }
63
63
 
64
+ function projectToolBroadcastConfig(broadcast = null) {
65
+ if (!broadcast || typeof broadcast !== 'object' || Array.isArray(broadcast)) return null;
66
+ return {
67
+ enabled: normalizeOptionalBoolean(broadcast.enabled, null),
68
+ audience: normalizeText(broadcast.audience, null),
69
+ replyPolicy: normalizeText(broadcast.replyPolicy, null),
70
+ excludeSelf: normalizeOptionalBoolean(broadcast.excludeSelf, null),
71
+ };
72
+ }
73
+
64
74
  function projectWorldFeedbackSummary(summary = null) {
65
75
  if (!summary || typeof summary !== 'object' || Array.isArray(summary)) return null;
66
76
  return {
@@ -90,6 +100,20 @@ function projectOrchestration(orchestration = null) {
90
100
  };
91
101
  }
92
102
 
103
+ function projectToolAction(action = null) {
104
+ if (!action || typeof action !== 'object' || Array.isArray(action)) return null;
105
+ return {
106
+ tool: normalizeText(action.tool, null),
107
+ summary: normalizeText(action.summary, null),
108
+ payload: action.payload && typeof action.payload === 'object' && !Array.isArray(action.payload)
109
+ ? action.payload
110
+ : {},
111
+ payloadTemplate: action.payloadTemplate && typeof action.payloadTemplate === 'object' && !Array.isArray(action.payloadTemplate)
112
+ ? action.payloadTemplate
113
+ : {},
114
+ };
115
+ }
116
+
93
117
  function projectRequestChatPayload(
94
118
  requestChat = null,
95
119
  {
@@ -198,17 +222,66 @@ function projectToolCandidateDeliverySummary(
198
222
 
199
223
  export function projectToolWorldList(worldDirectory = {}) {
200
224
  const worlds = Array.isArray(worldDirectory.items)
201
- ? [...worldDirectory.items]
202
- .map((world) => ({
203
- worldId: world.worldId,
204
- displayName: world.displayName,
205
- worldContextText: normalizeText(world.worldContextText, null),
206
- hotness: normalizeInteger(world.hotness, 0),
207
- }))
208
- .sort((left, right) => right.hotness - left.hotness || left.displayName.localeCompare(right.displayName))
225
+ ? worldDirectory.items.map((world) => ({
226
+ worldId: world.worldId,
227
+ displayName: world.displayName,
228
+ summary: normalizeText(world.summary, null),
229
+ worldContextText: normalizeText(world.worldContextText, null),
230
+ tags: normalizeStringList(world.tags),
231
+ hotness: normalizeInteger(world.hotness, 0),
232
+ activatedMemberCount: normalizeInteger(world.activatedMemberCount, normalizeInteger(world.hotness, 0)),
233
+ reasonSummary: normalizeText(world.reasonSummary, null),
234
+ detailAction: projectToolAction(world.detailAction),
235
+ joinAction: projectToolAction(world.joinAction),
236
+ }))
237
+ : [];
238
+
239
+ return {
240
+ worlds,
241
+ mode: normalizeText(worldDirectory.mode, 'browse'),
242
+ query: normalizeText(worldDirectory.query, null),
243
+ sort: normalizeText(worldDirectory.sort, 'hot'),
244
+ nextAction: normalizeText(worldDirectory.nextAction, 'inspect_world_detail_or_join_world'),
245
+ pagination: worldDirectory.pagination && typeof worldDirectory.pagination === 'object'
246
+ ? {
247
+ page: normalizeInteger(worldDirectory.pagination.page, 1),
248
+ totalPages: normalizeInteger(worldDirectory.pagination.totalPages, 0),
249
+ totalCount: normalizeInteger(worldDirectory.pagination.totalCount, worlds.length),
250
+ }
251
+ : {
252
+ page: 1,
253
+ totalPages: worlds.length > 0 ? 1 : 0,
254
+ totalCount: worlds.length,
255
+ },
256
+ };
257
+ }
258
+
259
+ export function projectToolWorldSearchResponse(worldDirectory = {}, { accountId = null } = {}) {
260
+ const worlds = Array.isArray(worldDirectory.items)
261
+ ? worldDirectory.items.map((world) => ({
262
+ worldId: world.worldId,
263
+ displayName: world.displayName,
264
+ summary: normalizeText(world.summary, null),
265
+ worldContextText: normalizeText(world.worldContextText, null),
266
+ tags: normalizeStringList(world.tags),
267
+ hotness: normalizeInteger(world.hotness, 0),
268
+ activatedMemberCount: normalizeInteger(world.activatedMemberCount, normalizeInteger(world.hotness, 0)),
269
+ matchScore: normalizeInteger(world.matchScore, 0),
270
+ matchedFieldIds: normalizeStringList(world.matchedFieldIds),
271
+ matchedTerms: normalizeStringList(world.matchedTerms),
272
+ reasonSummary: normalizeText(world.reasonSummary, null),
273
+ detailAction: projectToolAction(world.detailAction),
274
+ joinAction: projectToolAction(world.joinAction),
275
+ }))
209
276
  : [];
210
277
 
211
278
  return {
279
+ accountId: normalizeText(accountId, null),
280
+ status: normalizeText(worldDirectory.status, worlds.length > 0 ? 'search_ready' : 'no_matches'),
281
+ mode: normalizeText(worldDirectory.mode, 'browse'),
282
+ query: normalizeText(worldDirectory.query, null),
283
+ sort: normalizeText(worldDirectory.sort, 'match'),
284
+ nextAction: normalizeText(worldDirectory.nextAction, worlds.length > 0 ? 'inspect_world_detail_or_join_world' : 'broaden_world_search'),
212
285
  worlds,
213
286
  pagination: worldDirectory.pagination && typeof worldDirectory.pagination === 'object'
214
287
  ? {
@@ -224,7 +297,7 @@ export function projectToolWorldList(worldDirectory = {}) {
224
297
  };
225
298
  }
226
299
 
227
- export function projectToolWorldDetail(worldDetail = {}) {
300
+ export function projectToolWorldDetail(worldDetail = {}, { accountId = null } = {}) {
228
301
  return {
229
302
  worldId: worldDetail.worldId,
230
303
  displayName: normalizeText(worldDetail.world?.displayName, worldDetail.displayName || ''),
@@ -240,6 +313,15 @@ export function projectToolWorldDetail(worldDetail = {}) {
240
313
  enabled: normalizeOptionalBoolean(worldDetail.management?.enabled, normalizeOptionalBoolean(worldDetail.enabled, null)),
241
314
  status: normalizeText(worldDetail.management?.status, normalizeText(worldDetail.statusLabel, null)),
242
315
  participantContextField: projectParticipantContextField(worldDetail.participantContextField),
316
+ memberSearchAction: {
317
+ tool: 'claworld_search_world_members',
318
+ summary: 'After joining this world, search joined members by profile match or likes.',
319
+ payloadTemplate: {
320
+ ...(normalizeText(accountId, null) ? { accountId: normalizeText(accountId, null) } : {}),
321
+ worldId: worldDetail.worldId,
322
+ query: ':query',
323
+ },
324
+ },
243
325
  };
244
326
  }
245
327
 
@@ -259,13 +341,69 @@ function projectToolCandidateSummary(summary = {}, index = 0) {
259
341
  };
260
342
  }
261
343
 
262
- function projectToolCandidateFeed(joinResult = {}) {
263
- const candidateDelivery = joinResult.candidateDelivery && typeof joinResult.candidateDelivery === 'object'
264
- ? joinResult.candidateDelivery
265
- : null;
266
- const candidateFeed = joinResult.candidateFeed && typeof joinResult.candidateFeed === 'object'
267
- ? joinResult.candidateFeed
344
+ function projectCandidateProfileSummary(summary = {}) {
345
+ return {
346
+ displayName: normalizeText(summary.displayName, null),
347
+ headline: normalizeText(summary.headline, null),
348
+ requiredFields: Array.isArray(summary.requiredFields)
349
+ ? summary.requiredFields.map((field) => ({
350
+ fieldId: normalizeText(field.fieldId, null),
351
+ label: normalizeText(field.label, normalizeText(field.fieldId, null)),
352
+ value: Array.isArray(field.value) ? normalizeStringList(field.value) : normalizeText(field.value, null),
353
+ }))
354
+ : [],
355
+ optionalFields: Array.isArray(summary.optionalFields)
356
+ ? summary.optionalFields.map((field) => ({
357
+ fieldId: normalizeText(field.fieldId, null),
358
+ label: normalizeText(field.label, normalizeText(field.fieldId, null)),
359
+ value: Array.isArray(field.value) ? normalizeStringList(field.value) : normalizeText(field.value, null),
360
+ }))
361
+ : [],
362
+ };
363
+ }
364
+
365
+ function resolveCandidateProjectionPayload(payload = {}) {
366
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
367
+ return {
368
+ worldId: null,
369
+ nextAction: null,
370
+ candidateFeed: null,
371
+ candidateDelivery: null,
372
+ requestChatAction: null,
373
+ };
374
+ }
375
+
376
+ const candidateFeed = payload.candidateFeed && typeof payload.candidateFeed === 'object' && !Array.isArray(payload.candidateFeed)
377
+ ? payload.candidateFeed
378
+ : Array.isArray(payload.candidates)
379
+ ? payload
380
+ : null;
381
+ const candidateDelivery = payload.candidateDelivery && typeof payload.candidateDelivery === 'object' && !Array.isArray(payload.candidateDelivery)
382
+ ? payload.candidateDelivery
383
+ : candidateFeed?.candidateDelivery && typeof candidateFeed.candidateDelivery === 'object' && !Array.isArray(candidateFeed.candidateDelivery)
384
+ ? candidateFeed.candidateDelivery
385
+ : null;
386
+ const candidateModelRequestChatAction = candidateFeed?.candidateModel && typeof candidateFeed.candidateModel === 'object' && !Array.isArray(candidateFeed.candidateModel)
387
+ ? candidateFeed.candidateModel.requestChatAction
268
388
  : null;
389
+
390
+ return {
391
+ worldId: normalizeText(payload.worldId, normalizeText(candidateFeed?.worldId, normalizeText(candidateDelivery?.worldId, null))),
392
+ nextAction: normalizeText(payload.nextAction, normalizeText(candidateFeed?.nextAction, normalizeText(candidateDelivery?.nextAction, null))),
393
+ candidateFeed,
394
+ candidateDelivery,
395
+ requestChatAction: payload.requestChatAction && typeof payload.requestChatAction === 'object' && !Array.isArray(payload.requestChatAction)
396
+ ? payload.requestChatAction
397
+ : candidateDelivery?.requestChatAction && typeof candidateDelivery.requestChatAction === 'object' && !Array.isArray(candidateDelivery.requestChatAction)
398
+ ? candidateDelivery.requestChatAction
399
+ : candidateModelRequestChatAction && typeof candidateModelRequestChatAction === 'object' && !Array.isArray(candidateModelRequestChatAction)
400
+ ? candidateModelRequestChatAction
401
+ : null,
402
+ };
403
+ }
404
+
405
+ function projectToolCandidateFeed(payload = {}) {
406
+ const { candidateFeed, candidateDelivery } = resolveCandidateProjectionPayload(payload);
269
407
  const candidateSummaries = Array.isArray(candidateDelivery?.candidateSummaries)
270
408
  ? candidateDelivery.candidateSummaries.map((summary, index) => projectToolCandidateSummary(summary, index))
271
409
  : Array.isArray(candidateFeed?.candidates)
@@ -273,6 +411,7 @@ function projectToolCandidateFeed(joinResult = {}) {
273
411
  candidateId: candidate.candidateId,
274
412
  displayName: candidate.profileSummary?.displayName,
275
413
  agentCode: normalizeText(candidate.agentCode, candidate.requestChat?.agentCode || null),
414
+ worldRole: candidate.worldRole,
276
415
  headline: candidate.profileSummary?.headline,
277
416
  online: candidate.online === true,
278
417
  rank: candidate.rank,
@@ -302,13 +441,52 @@ function projectToolCandidateFeed(joinResult = {}) {
302
441
  };
303
442
  }
304
443
 
444
+ function projectToolCandidateFlowResponse(payload = {}, { accountId = null } = {}) {
445
+ const {
446
+ worldId,
447
+ nextAction,
448
+ candidateFeed,
449
+ candidateDelivery,
450
+ requestChatAction,
451
+ } = resolveCandidateProjectionPayload(payload);
452
+ const projectedFeed = projectToolCandidateFeed({ candidateFeed, candidateDelivery });
453
+ const projectedDelivery = projectToolCandidateDeliverySummary(candidateDelivery, { accountId });
454
+ const projectedRequestChatAction = projectRequestChatAction(requestChatAction, { accountId });
455
+
456
+ return {
457
+ worldId: normalizeText(worldId, normalizeText(projectedDelivery?.worldId, null)),
458
+ nextAction: normalizeText(nextAction, normalizeText(projectedFeed?.nextAction, normalizeText(projectedDelivery?.nextAction, null))),
459
+ candidateFeed: projectedFeed,
460
+ requestChatTool: 'claworld_request_chat',
461
+ candidateDelivery: projectedDelivery,
462
+ requestChatAction: projectedRequestChatAction,
463
+ };
464
+ }
465
+
466
+ export function projectToolCandidateFeedResponse(candidateFeedPayload = {}, { accountId = null } = {}) {
467
+ const candidateFlow = projectToolCandidateFlowResponse(candidateFeedPayload, { accountId });
468
+
469
+ return {
470
+ status: normalizeText(candidateFeedPayload.status, normalizeText(candidateFlow.candidateFeed?.status, 'no_candidates_ready')),
471
+ worldId: candidateFlow.worldId,
472
+ accountId: normalizeText(accountId, null),
473
+ nextAction: candidateFlow.nextAction,
474
+ candidateFeed: candidateFlow.candidateFeed,
475
+ requestChatTool: candidateFlow.requestChatTool,
476
+ candidateDelivery: candidateFlow.candidateDelivery,
477
+ requestChatAction: candidateFlow.requestChatAction,
478
+ };
479
+ }
480
+
305
481
  export function projectToolJoinWorldResponse(
306
482
  joinResult = {},
307
483
  { accountId = null } = {},
308
484
  ) {
485
+ const candidateFlow = projectToolCandidateFlowResponse(joinResult, { accountId });
486
+
309
487
  return {
310
488
  status: joinResult.membershipStatus === 'active' ? 'joined' : 'accepted',
311
- worldId: joinResult.worldId,
489
+ worldId: normalizeText(joinResult.worldId, candidateFlow.worldId),
312
490
  accountId: normalizeText(accountId, null),
313
491
  worldRole: projectWorldRole(joinResult.worldRole, null),
314
492
  membershipStatus: joinResult.membershipStatus || 'unknown',
@@ -317,10 +495,10 @@ export function projectToolJoinWorldResponse(
317
495
  joinResult.membership?.participantContextText || null,
318
496
  ),
319
497
  nextAction: normalizeText(joinResult.nextAction, 'review_candidate_feed'),
320
- candidateFeed: projectToolCandidateFeed(joinResult),
321
- requestChatTool: 'claworld_request_chat',
322
- candidateDelivery: projectToolCandidateDeliverySummary(joinResult.candidateDelivery, { accountId }),
323
- requestChatAction: projectRequestChatAction(joinResult.requestChatAction, { accountId }),
498
+ candidateFeed: candidateFlow.candidateFeed,
499
+ requestChatTool: candidateFlow.requestChatTool,
500
+ candidateDelivery: candidateFlow.candidateDelivery,
501
+ requestChatAction: candidateFlow.requestChatAction,
324
502
  orchestration: projectOrchestration(joinResult.orchestration),
325
503
  };
326
504
  }
@@ -356,6 +534,7 @@ export function projectToolOwnedWorldsResponse(payload = {}, { accountId = null
356
534
  worldRole: projectWorldRole(world.worldRole, null),
357
535
  createdAt: normalizeText(world.createdAt, null),
358
536
  updatedAt: normalizeText(world.updatedAt, null),
537
+ broadcast: projectToolBroadcastConfig(world.broadcast),
359
538
  stats: projectWorldStats(world.stats),
360
539
  }))
361
540
  : [];
@@ -380,10 +559,59 @@ export function projectToolManagedWorldResponse(world = {}, { accountId = null }
380
559
  createdAt: normalizeText(world.createdAt, null),
381
560
  updatedAt: normalizeText(world.updatedAt, null),
382
561
  participantContextField: projectParticipantContextField(world.participantContextField),
562
+ broadcast: projectToolBroadcastConfig(world.broadcast),
383
563
  stats: projectWorldStats(world.stats),
384
564
  };
385
565
  }
386
566
 
567
+ function projectToolWorldBroadcastRequestItem(item = {}) {
568
+ return {
569
+ agentId: normalizeText(item.agentId, null),
570
+ status: normalizeText(item.status, null),
571
+ verdict: normalizeText(item.verdict, null),
572
+ chatRequest: projectChatRequestItem(item.chatRequest),
573
+ kickoff: projectChatRequestKickoff(item.kickoff),
574
+ };
575
+ }
576
+
577
+ function projectToolWorldBroadcastFailureItem(item = {}) {
578
+ return {
579
+ agentId: normalizeText(item.agentId, null),
580
+ status: normalizeText(item.status, 'failed'),
581
+ httpStatus: normalizeOptionalInteger(item.httpStatus, null),
582
+ error: normalizeText(item.error, null),
583
+ reason: normalizeText(item.reason, null),
584
+ message: normalizeText(item.message, null),
585
+ };
586
+ }
587
+
588
+ export function projectToolWorldBroadcastResponse(payload = {}, { accountId = null } = {}) {
589
+ return {
590
+ accountId: normalizeText(accountId, null),
591
+ status: normalizeText(payload.status, null),
592
+ worldId: normalizeText(payload.worldId, null),
593
+ senderAgentId: normalizeText(payload.senderAgentId, null),
594
+ senderRole: projectWorldRole(payload.senderRole, null),
595
+ audience: normalizeText(payload.audience, null),
596
+ excludeSelf: normalizeOptionalBoolean(payload.excludeSelf, null),
597
+ eligibility: normalizeText(payload.eligibility, null),
598
+ broadcastId: normalizeText(payload.broadcastId, null),
599
+ totalTargets: normalizeOptionalInteger(payload.totalTargets, null),
600
+ createdCount: normalizeOptionalInteger(payload.createdCount, null),
601
+ failedCount: normalizeOptionalInteger(payload.failedCount, null),
602
+ pendingCount: normalizeOptionalInteger(payload.pendingCount, null),
603
+ autoAcceptedCount: normalizeOptionalInteger(payload.autoAcceptedCount, null),
604
+ rejectedCount: normalizeOptionalInteger(payload.rejectedCount, null),
605
+ nextAction: normalizeText(payload.nextAction, null),
606
+ requests: Array.isArray(payload.requests)
607
+ ? payload.requests.map((item) => projectToolWorldBroadcastRequestItem(item))
608
+ : [],
609
+ failures: Array.isArray(payload.failures)
610
+ ? payload.failures.map((item) => projectToolWorldBroadcastFailureItem(item))
611
+ : [],
612
+ };
613
+ }
614
+
387
615
  function projectToolWorldMembershipSummary(membership = {}) {
388
616
  return {
389
617
  membershipId: normalizeText(membership.membershipId, null),
@@ -419,6 +647,34 @@ export function projectToolWorldMembershipResponse(payload = {}, { accountId = n
419
647
  };
420
648
  }
421
649
 
650
+ export function projectToolWorldMemberSearchResponse(payload = {}, { accountId = null } = {}) {
651
+ return {
652
+ accountId: normalizeText(accountId, null),
653
+ status: normalizeText(payload.status, 'no_matches'),
654
+ worldId: normalizeText(payload.worldId, null),
655
+ query: normalizeText(payload.query, null),
656
+ sort: normalizeText(payload.sort, 'match'),
657
+ limit: normalizeInteger(payload.limit, 0),
658
+ totalMatches: normalizeInteger(payload.totalMatches, Array.isArray(payload.items) ? payload.items.length : 0),
659
+ nextAction: normalizeText(payload.nextAction, null),
660
+ members: Array.isArray(payload.items)
661
+ ? payload.items.map((item, index) => ({
662
+ candidateId: normalizeText(item.membershipId, `candidate_${index + 1}`),
663
+ displayName: normalizeText(item.displayName, `Candidate ${index + 1}`),
664
+ agentCode: normalizeText(item.agentCode, null)?.toUpperCase() || null,
665
+ headline: normalizeText(item.headline, null),
666
+ online: item.online === true,
667
+ score: normalizeInteger(item.score, 0),
668
+ matchedFieldIds: normalizeStringList(item.matchedFieldIds),
669
+ reasonSummary: normalizeText(item.reasonSummary, null),
670
+ profileSummary: projectCandidateProfileSummary(item.profileSummary || {}),
671
+ worldFeedbackSummary: projectWorldFeedbackSummary(item.worldFeedbackSummary),
672
+ requestChat: projectRequestChatPayload(item.requestChat, { accountId }),
673
+ }))
674
+ : [],
675
+ };
676
+ }
677
+
422
678
  export function projectToolFeedbackSubmissionResponse(result = {}) {
423
679
  const feedback = result.feedback && typeof result.feedback === 'object' ? result.feedback : {};
424
680
  const reporter = feedback.reporter && typeof feedback.reporter === 'object' ? feedback.reporter : {};
@@ -602,6 +858,7 @@ function projectChatInboxCountBlock(counts = {}, fallback = {}) {
602
858
  chatStatusCounts: counts.chatStatusCounts && typeof counts.chatStatusCounts === 'object' && !Array.isArray(counts.chatStatusCounts)
603
859
  ? {
604
860
  opening: normalizeInteger(counts.chatStatusCounts.opening, 0),
861
+ ending: normalizeInteger(counts.chatStatusCounts.ending, 0),
605
862
  active: normalizeInteger(counts.chatStatusCounts.active, 0),
606
863
  silent: normalizeInteger(counts.chatStatusCounts.silent, 0),
607
864
  kickoff_failed: normalizeInteger(counts.chatStatusCounts.kickoff_failed, 0),
@@ -609,6 +866,7 @@ function projectChatInboxCountBlock(counts = {}, fallback = {}) {
609
866
  }
610
867
  : {
611
868
  opening: 0,
869
+ ending: 0,
612
870
  active: 0,
613
871
  silent: 0,
614
872
  kickoff_failed: 0,
@@ -14,9 +14,12 @@ export const CLAWORLD_FEEDBACK_TOOL_NAMES = Object.freeze([
14
14
  ]);
15
15
 
16
16
  export const CLAWORLD_WORLD_TOOL_NAMES = Object.freeze([
17
+ 'claworld_search_worlds',
17
18
  'claworld_list_worlds',
18
19
  'claworld_get_world_detail',
19
20
  'claworld_join_world',
21
+ 'claworld_search_world_members',
22
+ 'claworld_get_candidate_feed',
20
23
  ]);
21
24
 
22
25
  export const CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES = Object.freeze([