@xfxstudio/claworld 2026.4.28-testing → 2026.4.28-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.
@@ -1336,6 +1336,22 @@ export class ClaworldRelayClient extends EventEmitter {
1336
1336
  });
1337
1337
  }
1338
1338
 
1339
+ async closeConversation({ actorAgentId, conversationKey = null, localSessionKey = null } = {}) {
1340
+ return await this.requestJson('/v1/chat-requests/conversations/close', {
1341
+ method: 'POST',
1342
+ headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
1343
+ body: JSON.stringify({
1344
+ actorAgentId,
1345
+ ...(conversationKey ? { conversationKey } : {}),
1346
+ ...(localSessionKey ? { localSessionKey } : {}),
1347
+ }),
1348
+ }, {
1349
+ code: 'relay_conversation_close_failed',
1350
+ message: 'failed to close relay conversation',
1351
+ publicMessage: 'failed to close relay conversation',
1352
+ });
1353
+ }
1354
+
1339
1355
  async deliverMessage({ fromAgentId, targetAgentId, clientMessageId = null, payload = {}, conversation = {} } = {}) {
1340
1356
  const resolvedClientMessageId = requireClientMessageId(clientMessageId);
1341
1357
  const result = await this.requestJson('/v1/orchestration/messages', {
@@ -124,10 +124,10 @@ export async function submitFeedbackReport({
124
124
  tags: normalizeStringList(normalizedContext.tags),
125
125
  metadata: normalizeObject(normalizedContext.metadata),
126
126
  },
127
- source: 'openclaw_tool',
127
+ source: 'openclaw_runtime',
128
128
  runtimeContext: {
129
129
  channelId: 'claworld',
130
- toolName: 'claworld_submit_feedback',
130
+ toolName: 'claworld_feedback_helper',
131
131
  toolCallId: normalizeText(toolCallId, null),
132
132
  ...diagnostics,
133
133
  toolContractVersion: normalizeText(toolContractVersion, null),
@@ -3,7 +3,7 @@ import { buildRuntimeAuthHeaders } from '../plugin/account-identity.js';
3
3
  import { createRuntimeBoundaryError } from '../../lib/runtime-errors.js';
4
4
  import { extractBackendErrorContext } from './backend-error-context.js';
5
5
  import {
6
- buildCandidateDeliverySummary as buildBackendCandidateDeliverySummary,
6
+ buildWorldSelectionPrompt as buildBackendWorldSelectionPrompt,
7
7
  resolveWorldSelection as resolveBackendWorldSelection,
8
8
  } from '../../product-shell/contracts/world-orchestration.js';
9
9
 
@@ -203,12 +203,6 @@ function normalizeWorldDetail(payload = {}) {
203
203
  };
204
204
  }
205
205
 
206
- function normalizeNumber(value, fallback = null) {
207
- const parsed = Number(value);
208
- if (!Number.isFinite(parsed)) return fallback;
209
- return parsed;
210
- }
211
-
212
206
  function normalizeProfileSummaryField(field = {}, index = 0) {
213
207
  const fieldId = normalizeText(field.fieldId || field.id, `field_${index + 1}`);
214
208
  const value = Array.isArray(field.value)
@@ -226,7 +220,7 @@ function normalizeProfileSummaryField(field = {}, index = 0) {
226
220
  };
227
221
  }
228
222
 
229
- function normalizeCandidateProfileSummary(summary = {}) {
223
+ function normalizeMemberProfileSummary(summary = {}) {
230
224
  return {
231
225
  displayName: normalizeText(summary.displayName, null),
232
226
  headline: normalizeText(summary.headline, null),
@@ -265,102 +259,6 @@ function normalizeBroadcastConfig(broadcast = null) {
265
259
  };
266
260
  }
267
261
 
268
- function normalizeCompatibilitySignal(signal = {}, index = 0) {
269
- return {
270
- signalId: normalizeText(signal.signalId, `signal_${index + 1}`),
271
- type: normalizeText(signal.type, 'world_ready'),
272
- fieldIds: normalizeStringList(signal.fieldIds),
273
- score: normalizeNumber(signal.score, 0),
274
- summary: normalizeText(signal.summary, ''),
275
- };
276
- }
277
-
278
- function normalizeDeliveryReason(reason = {}) {
279
- return {
280
- code: normalizeText(reason.code, null),
281
- matchedFieldIds: normalizeStringList(reason.matchedFieldIds),
282
- summary: normalizeText(reason.summary, ''),
283
- };
284
- }
285
-
286
- function normalizeCandidate(candidate = {}, index = 0) {
287
- const normalizedRank = normalizeNumber(candidate.rank, null);
288
- const displayName = normalizeText(
289
- candidate.displayName || candidate.profileSummary?.displayName || candidate.requestChat?.displayName,
290
- null,
291
- );
292
- const agentCode = normalizeText(
293
- candidate.agentCode || candidate.requestChat?.agentCode,
294
- null,
295
- )?.toUpperCase() || null;
296
- const requestChat = displayName && agentCode
297
- ? {
298
- worldId: normalizeText(candidate.requestChat?.worldId, normalizeText(candidate.worldId, 'unknown-world')),
299
- displayName,
300
- agentCode,
301
- }
302
- : null;
303
-
304
- return {
305
- candidateId: normalizeText(candidate.candidateId, `candidate_${index + 1}`),
306
- worldId: normalizeText(candidate.worldId, 'unknown-world'),
307
- worldRole: normalizeWorldRole(candidate.worldRole, null),
308
- sourceMembershipId: normalizeText(candidate.sourceMembershipId, null),
309
- online: candidate.online === true,
310
- displayName,
311
- agentCode,
312
- requestChat,
313
- profileSummary: normalizeCandidateProfileSummary(candidate.profileSummary),
314
- compatibilitySignals: Array.isArray(candidate.compatibilitySignals)
315
- ? candidate.compatibilitySignals.map((signal, signalIndex) => normalizeCompatibilitySignal(signal, signalIndex))
316
- : [],
317
- deliveryReason: normalizeDeliveryReason(candidate.deliveryReason),
318
- worldFeedbackSummary: candidate.worldFeedbackSummary && typeof candidate.worldFeedbackSummary === 'object'
319
- ? {
320
- likesReceived: normalizeInteger(candidate.worldFeedbackSummary.likesReceived, 0),
321
- dislikesReceived: normalizeInteger(candidate.worldFeedbackSummary.dislikesReceived, 0),
322
- }
323
- : {
324
- likesReceived: 0,
325
- dislikesReceived: 0,
326
- },
327
- expiresAt: normalizeText(candidate.expiresAt, null),
328
- joinedAt: normalizeText(candidate.joinedAt, null),
329
- rank: normalizedRank == null ? null : Math.max(1, Math.trunc(normalizedRank)),
330
- score: normalizeNumber(candidate.score, null),
331
- };
332
- }
333
-
334
- function normalizeCandidateFeedResponse(payload = {}, { worldId = null, agentId = null } = {}) {
335
- const candidates = Array.isArray(payload.candidates)
336
- ? payload.candidates.map((candidate, index) => normalizeCandidate(candidate, index))
337
- : [];
338
-
339
- return {
340
- worldId: normalizeText(payload.worldId, worldId || 'unknown-world'),
341
- agentId: normalizeText(payload.agentId, agentId || null),
342
- viewerMembershipId: normalizeText(payload.viewerMembershipId, null),
343
- generatedAt: normalizeText(payload.generatedAt, null),
344
- expiresAt: normalizeText(payload.expiresAt, null),
345
- deliveryMode: normalizeText(payload.deliveryMode, 'agent_review_before_live_session'),
346
- nextAction: normalizeText(
347
- payload.nextAction,
348
- candidates.length > 0 ? 'review_candidates_then_request_chat' : 'wait_for_more_candidates',
349
- ),
350
- candidateDelivery: payload.candidateDelivery && typeof payload.candidateDelivery === 'object'
351
- ? payload.candidateDelivery
352
- : null,
353
- candidateSource: normalizeText(payload.candidateSource, 'active_memberships_online'),
354
- candidateModel: payload.candidateModel && typeof payload.candidateModel === 'object' ? payload.candidateModel : {},
355
- strategy: payload.strategy && typeof payload.strategy === 'object' ? payload.strategy : {},
356
- limit: normalizeInteger(payload.limit, candidates.length),
357
- totalCandidates: normalizeInteger(payload.totalCandidates, candidates.length),
358
- status: normalizeText(payload.status, candidates.length > 0 ? 'feed_ready' : 'no_candidates_ready'),
359
- candidates,
360
- };
361
- }
362
-
363
-
364
262
  function normalizeActionPayload(value = null) {
365
263
  return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
366
264
  }
@@ -370,8 +268,9 @@ export function normalizeWorldJoinResponse(payload = {}, { worldId = null, agent
370
268
  const normalizedWorldId = normalizeText(payload.worldId, worldId || 'unknown-world');
371
269
  const normalizedAgentId = normalizeText(payload.agentId || membership?.agentId, agentId || null);
372
270
  const membershipStatus = normalizeText(payload.membershipStatus || membership?.status, 'unknown');
271
+ const responseStatus = normalizeText(payload.status, membershipStatus === 'active' ? 'active' : 'accepted');
373
272
  return {
374
- status: normalizeText(payload.status, membershipStatus === 'active' ? 'joined' : 'accepted'),
273
+ status: responseStatus,
375
274
  worldId: normalizedWorldId,
376
275
  agentId: normalizedAgentId,
377
276
  worldRole: normalizeWorldRole(payload.worldRole, null),
@@ -413,20 +312,6 @@ function summarizeProfileFields(fields = []) {
413
312
  .filter(Boolean);
414
313
  }
415
314
 
416
- function buildCandidateDeliverySummaryLine(candidateSummary = {}, index = 0) {
417
- return `${index + 1}. ${candidateSummary.summary}`;
418
- }
419
-
420
- export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail = null, limit = null } = {}) {
421
- if (candidateFeed?.candidateDelivery && typeof candidateFeed.candidateDelivery === 'object') {
422
- return candidateFeed.candidateDelivery;
423
- }
424
- if (worldDetail?.candidateDelivery && typeof worldDetail.candidateDelivery === 'object') {
425
- return worldDetail.candidateDelivery;
426
- }
427
- return buildBackendCandidateDeliverySummary(candidateFeed, { worldDetail, limit });
428
- }
429
-
430
315
  export function buildWorldSelectionPrompt(worldDirectory = {}) {
431
316
  return worldDirectory?.orchestration && typeof worldDirectory.orchestration === 'object'
432
317
  ? worldDirectory.orchestration
@@ -476,7 +361,10 @@ export function buildPostSetupWorldDirectory(payload = {}, {
476
361
  nextAction: normalizeText(payload.nextAction, items.length > 0 ? 'inspect_world_detail_or_join_world' : 'broaden_world_search'),
477
362
  orchestration: payload.orchestration && typeof payload.orchestration === 'object'
478
363
  ? payload.orchestration
479
- : null,
364
+ : buildBackendWorldSelectionPrompt({
365
+ items,
366
+ recommendedWorldId,
367
+ }),
480
368
  };
481
369
  }
482
370
 
@@ -495,7 +383,7 @@ function normalizeWorldMemberSearchItem(item = {}) {
495
383
  matchedFieldIds: normalizeStringList(item.matchedFieldIds),
496
384
  reasonSummary: normalizeText(item.reasonSummary, null),
497
385
  joinedAt: normalizeText(item.joinedAt, null),
498
- profileSummary: normalizeCandidateProfileSummary(item.profileSummary || {}),
386
+ profileSummary: normalizeMemberProfileSummary(item.profileSummary || {}),
499
387
  worldFeedbackSummary: item.worldFeedbackSummary && typeof item.worldFeedbackSummary === 'object' && !Array.isArray(item.worldFeedbackSummary)
500
388
  ? {
501
389
  likesReceived: normalizeInteger(item.worldFeedbackSummary.likesReceived, 0),
@@ -519,10 +407,10 @@ export function normalizeWorldMemberSearchResponse(payload = {}, { accountId = n
519
407
  accountId: normalizeText(accountId, null),
520
408
  worldId: normalizeText(payload.worldId, null),
521
409
  query: normalizeText(payload.query, null),
522
- sort: normalizeText(payload.sort, 'match'),
410
+ sort: normalizeText(payload.sort, 'relevance'),
523
411
  limit: normalizeInteger(payload.limit, items.length),
524
412
  totalMatches: normalizeInteger(payload.totalMatches, items.length),
525
- nextAction: normalizeText(payload.nextAction, items.length > 0 ? 'request_chat_with_selected_candidate' : 'broaden_search_or_refresh_candidate_feed'),
413
+ nextAction: normalizeText(payload.nextAction, items.length > 0 ? 'request_chat_with_selected_result' : 'broaden_search'),
526
414
  items,
527
415
  };
528
416
  }
@@ -647,6 +535,13 @@ export async function searchWorlds({
647
535
  accountId = null,
648
536
  runtimeConfig = null,
649
537
  query = null,
538
+ keywords = [],
539
+ topics = [],
540
+ location = null,
541
+ timeWindow = null,
542
+ intent = null,
543
+ desiredInteraction = null,
544
+ constraints = [],
650
545
  limit = null,
651
546
  sort = null,
652
547
  page = null,
@@ -668,6 +563,13 @@ export async function searchWorlds({
668
563
  }),
669
564
  body: JSON.stringify({
670
565
  query: normalizeText(query, null),
566
+ keywords: normalizeStringList(keywords),
567
+ topics: normalizeStringList(topics),
568
+ location: normalizeText(location, null),
569
+ timeWindow: normalizeText(timeWindow, null),
570
+ intent: normalizeText(intent, null),
571
+ desiredInteraction: normalizeText(desiredInteraction, null),
572
+ constraints: normalizeStringList(constraints),
671
573
  sort: normalizeText(sort, null),
672
574
  limit: limit == null ? null : normalizeInteger(limit, 0),
673
575
  page: page == null ? null : normalizeInteger(page, 0),
@@ -699,6 +601,13 @@ export async function search({
699
601
  worldId = null,
700
602
  agentId = null,
701
603
  query = null,
604
+ keywords = [],
605
+ topics = [],
606
+ location = null,
607
+ timeWindow = null,
608
+ intent = null,
609
+ desiredInteraction = null,
610
+ constraints = [],
702
611
  limit = null,
703
612
  sort = null,
704
613
  page = null,
@@ -723,6 +632,13 @@ export async function search({
723
632
  worldId: normalizeText(worldId, null),
724
633
  agentId: normalizeText(agentId, null),
725
634
  query: normalizeText(query, null),
635
+ keywords: normalizeStringList(keywords),
636
+ topics: normalizeStringList(topics),
637
+ location: normalizeText(location, null),
638
+ timeWindow: normalizeText(timeWindow, null),
639
+ intent: normalizeText(intent, null),
640
+ desiredInteraction: normalizeText(desiredInteraction, null),
641
+ constraints: normalizeStringList(constraints),
726
642
  sort: normalizeText(sort, null),
727
643
  limit: limit == null ? null : normalizeInteger(limit, 0),
728
644
  page: page == null ? null : normalizeInteger(page, 0),
@@ -749,94 +665,122 @@ export async function search({
749
665
  };
750
666
  }
751
667
 
752
- export async function joinWorld({
668
+ export async function getPublicProfile({
753
669
  cfg = {},
754
670
  accountId = null,
755
671
  runtimeConfig = null,
756
- worldId = null,
757
672
  agentId = null,
758
- participantContextText = null,
673
+ viewerAgentId = null,
759
674
  fetchImpl,
760
675
  logger = console,
761
676
  } = {}) {
762
677
  if (typeof fetchImpl !== 'function') {
763
- throw new Error('fetch is unavailable for claworld product-shell join helper');
678
+ throw new Error('fetch is unavailable for claworld public-profile helper');
764
679
  }
765
-
766
- const resolvedWorldId = normalizeText(worldId, null);
767
- if (!resolvedWorldId) {
768
- throw new Error('claworld product-shell join helper requires worldId');
769
- }
770
-
771
680
  const resolvedAgentId = normalizeText(agentId, null);
772
681
  if (!resolvedAgentId) {
773
- throw new Error('claworld product-shell join helper requires agentId');
682
+ throw new Error('claworld public-profile helper requires agentId');
774
683
  }
775
-
776
684
  const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
777
685
  const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
778
- const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
779
- method: 'POST',
686
+ const requestUrl = new URL(`${baseUrl}/v1/public-profiles/${encodeURIComponent(resolvedAgentId)}`);
687
+ const resolvedViewerAgentId = normalizeText(viewerAgentId, null);
688
+ if (resolvedViewerAgentId) requestUrl.searchParams.set('viewerAgentId', resolvedViewerAgentId);
689
+ const profileResult = await fetchJson(fetchImpl, requestUrl.toString(), {
780
690
  headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
781
691
  accept: 'application/json',
782
- 'content-type': 'application/json',
783
692
  ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
784
693
  }),
785
- body: JSON.stringify({
786
- agentId: resolvedAgentId,
787
- participantContextText: normalizeText(participantContextText, null),
788
- }),
789
694
  });
790
-
791
- if (!joinResult.ok) {
792
- logger.error?.('[claworld:product-shell] world join failed', {
793
- status: joinResult.status,
794
- worldId: resolvedWorldId,
795
- agentId: resolvedAgentId,
695
+ if (!profileResult.ok) {
696
+ logger.error?.('[claworld:product-shell] public profile fetch failed', {
697
+ status: profileResult.status,
796
698
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
797
- body: joinResult.body,
699
+ agentId: resolvedAgentId,
700
+ body: profileResult.body,
798
701
  });
799
- throw createProductShellHttpError('world_join', joinResult, {
702
+ throw createProductShellHttpError('public_profile', profileResult, {
800
703
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
801
- worldId: resolvedWorldId,
802
704
  });
803
705
  }
706
+ return {
707
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
708
+ ...profileResult.body,
709
+ };
710
+ }
804
711
 
805
- return normalizeWorldJoinResponse(joinResult.body, {
806
- worldId: resolvedWorldId,
807
- agentId: resolvedAgentId,
712
+ export async function lookupPublicProfile({
713
+ cfg = {},
714
+ accountId = null,
715
+ runtimeConfig = null,
716
+ identity = null,
717
+ viewerAgentId = null,
718
+ fetchImpl,
719
+ logger = console,
720
+ } = {}) {
721
+ if (typeof fetchImpl !== 'function') {
722
+ throw new Error('fetch is unavailable for claworld public-profile helper');
723
+ }
724
+ const resolvedIdentity = normalizeText(identity, null);
725
+ if (!resolvedIdentity) {
726
+ throw new Error('claworld public-profile lookup helper requires identity');
727
+ }
728
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
729
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
730
+ const requestUrl = new URL(`${baseUrl}/v1/public-profiles/lookup`);
731
+ requestUrl.searchParams.set('identity', resolvedIdentity);
732
+ const resolvedViewerAgentId = normalizeText(viewerAgentId, null);
733
+ if (resolvedViewerAgentId) requestUrl.searchParams.set('viewerAgentId', resolvedViewerAgentId);
734
+ const profileResult = await fetchJson(fetchImpl, requestUrl.toString(), {
735
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
736
+ accept: 'application/json',
737
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
738
+ }),
808
739
  });
740
+ if (!profileResult.ok) {
741
+ logger.error?.('[claworld:product-shell] public profile lookup failed', {
742
+ status: profileResult.status,
743
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
744
+ identity: resolvedIdentity,
745
+ body: profileResult.body,
746
+ });
747
+ throw createProductShellHttpError('public_profile_lookup', profileResult, {
748
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
749
+ });
750
+ }
751
+ return {
752
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
753
+ ...profileResult.body,
754
+ };
809
755
  }
810
756
 
811
- export async function searchWorldMembers({
757
+ export async function joinWorld({
812
758
  cfg = {},
813
759
  accountId = null,
814
760
  runtimeConfig = null,
815
761
  worldId = null,
816
762
  agentId = null,
817
- query = null,
818
- sort = null,
819
- limit = null,
763
+ participantContextText = null,
820
764
  fetchImpl,
821
765
  logger = console,
822
766
  } = {}) {
823
767
  if (typeof fetchImpl !== 'function') {
824
- throw new Error('fetch is unavailable for claworld product-shell member search helper');
768
+ throw new Error('fetch is unavailable for claworld product-shell join helper');
825
769
  }
826
770
 
827
771
  const resolvedWorldId = normalizeText(worldId, null);
828
772
  if (!resolvedWorldId) {
829
- throw new Error('claworld product-shell member search helper requires worldId');
773
+ throw new Error('claworld product-shell join helper requires worldId');
830
774
  }
831
775
 
832
776
  const resolvedAgentId = normalizeText(agentId, null);
833
777
  if (!resolvedAgentId) {
834
- throw new Error('claworld product-shell member search helper requires agentId');
778
+ throw new Error('claworld product-shell join helper requires agentId');
835
779
  }
836
780
 
837
781
  const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
838
782
  const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
839
- const searchResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/search`, {
783
+ const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
840
784
  method: 'POST',
841
785
  headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
842
786
  accept: 'application/json',
@@ -845,58 +789,65 @@ export async function searchWorldMembers({
845
789
  }),
846
790
  body: JSON.stringify({
847
791
  agentId: resolvedAgentId,
848
- query: normalizeText(query, null),
849
- sort: normalizeText(sort, null),
850
- limit: limit == null ? null : normalizeInteger(limit, 0),
792
+ participantContextText: normalizeText(participantContextText, null),
851
793
  }),
852
794
  });
853
795
 
854
- if (!searchResult.ok) {
855
- logger.error?.('[claworld:product-shell] world member search failed', {
856
- status: searchResult.status,
796
+ if (!joinResult.ok) {
797
+ logger.error?.('[claworld:product-shell] world join failed', {
798
+ status: joinResult.status,
857
799
  worldId: resolvedWorldId,
858
800
  agentId: resolvedAgentId,
859
801
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
860
- body: searchResult.body,
802
+ body: joinResult.body,
861
803
  });
862
- throw createProductShellHttpError('world_member_search', searchResult, {
804
+ throw createProductShellHttpError('world_join', joinResult, {
863
805
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
864
806
  worldId: resolvedWorldId,
865
807
  });
866
808
  }
867
809
 
868
- return normalizeWorldMemberSearchResponse(searchResult.body, {
869
- accountId: resolvedRuntimeConfig.accountId || accountId || null,
810
+ return normalizeWorldJoinResponse(joinResult.body, {
811
+ worldId: resolvedWorldId,
812
+ agentId: resolvedAgentId,
870
813
  });
871
814
  }
872
815
 
873
- export async function fetchWorldCandidateFeed({
816
+ export async function searchWorldMembers({
874
817
  cfg = {},
875
818
  accountId = null,
876
819
  runtimeConfig = null,
877
820
  worldId = null,
878
821
  agentId = null,
822
+ query = null,
823
+ keywords = [],
824
+ topics = [],
825
+ location = null,
826
+ timeWindow = null,
827
+ intent = null,
828
+ desiredInteraction = null,
829
+ constraints = [],
830
+ sort = null,
879
831
  limit = null,
880
832
  fetchImpl,
881
833
  logger = console,
882
834
  } = {}) {
883
835
  if (typeof fetchImpl !== 'function') {
884
- throw new Error('fetch is unavailable for claworld product-shell candidate feed helper');
836
+ throw new Error('fetch is unavailable for claworld product-shell member search helper');
885
837
  }
886
838
 
887
839
  const resolvedWorldId = normalizeText(worldId, null);
888
840
  if (!resolvedWorldId) {
889
- throw new Error('claworld product-shell candidate feed helper requires worldId');
841
+ throw new Error('claworld product-shell member search helper requires worldId');
890
842
  }
891
843
 
892
844
  const resolvedAgentId = normalizeText(agentId, null);
893
845
  if (!resolvedAgentId) {
894
- throw new Error('claworld product-shell candidate feed helper requires agentId');
846
+ throw new Error('claworld product-shell member search helper requires agentId');
895
847
  }
896
848
 
897
849
  const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
898
850
  const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
899
- const normalizedLimit = normalizeInteger(limit, 0);
900
851
  const searchResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/search`, {
901
852
  method: 'POST',
902
853
  headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
@@ -906,60 +857,36 @@ export async function fetchWorldCandidateFeed({
906
857
  }),
907
858
  body: JSON.stringify({
908
859
  agentId: resolvedAgentId,
909
- query: null,
910
- sort: 'match',
911
- limit: normalizedLimit > 0 ? normalizedLimit : null,
860
+ query: normalizeText(query, null),
861
+ keywords: normalizeStringList(keywords),
862
+ topics: normalizeStringList(topics),
863
+ location: normalizeText(location, null),
864
+ timeWindow: normalizeText(timeWindow, null),
865
+ intent: normalizeText(intent, null),
866
+ desiredInteraction: normalizeText(desiredInteraction, null),
867
+ constraints: normalizeStringList(constraints),
868
+ sort: normalizeText(sort, null),
869
+ limit: limit == null ? null : normalizeInteger(limit, 0),
912
870
  }),
913
871
  });
914
872
 
915
873
  if (!searchResult.ok) {
916
- logger.error?.('[claworld:product-shell] candidate feed compatibility search failed', {
874
+ logger.error?.('[claworld:product-shell] world member search failed', {
917
875
  status: searchResult.status,
918
876
  worldId: resolvedWorldId,
919
877
  agentId: resolvedAgentId,
920
878
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
921
879
  body: searchResult.body,
922
880
  });
923
- throw createProductShellHttpError('world_candidate_feed', searchResult, {
881
+ throw createProductShellHttpError('world_member_search', searchResult, {
924
882
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
925
883
  worldId: resolvedWorldId,
926
884
  });
927
885
  }
928
886
 
929
- const searchPayload = searchResult.body && typeof searchResult.body === 'object' ? searchResult.body : {};
930
- const normalizedSearch = normalizeWorldMemberSearchResponse(searchPayload, {
887
+ return normalizeWorldMemberSearchResponse(searchResult.body, {
931
888
  accountId: resolvedRuntimeConfig.accountId || accountId || null,
932
889
  });
933
- return normalizeCandidateFeedResponse({
934
- worldId: resolvedWorldId,
935
- agentId: resolvedAgentId,
936
- viewerMembershipId: searchPayload.viewerMembershipId,
937
- generatedAt: searchPayload.generatedAt,
938
- limit: normalizedSearch.limit,
939
- totalCandidates: normalizedSearch.totalMatches,
940
- candidateSource: searchPayload.candidateSource || 'active_memberships',
941
- status: normalizedSearch.items.length > 0 ? 'feed_ready' : 'no_candidates_ready',
942
- nextAction: normalizedSearch.nextAction,
943
- candidates: normalizedSearch.items.map((item, index) => ({
944
- candidateId: item.membershipId || `candidate_${index + 1}`,
945
- sourceMembershipId: item.membershipId || null,
946
- worldId: item.worldId || resolvedWorldId,
947
- online: item.online === true,
948
- rank: index + 1,
949
- score: item.score,
950
- agentCode: item.agentCode,
951
- requestChat: item.requestChat,
952
- profileSummary: item.profileSummary,
953
- deliveryReason: {
954
- summary: item.reasonSummary || item.headline || null,
955
- },
956
- worldFeedbackSummary: item.worldFeedbackSummary,
957
- joinedAt: item.joinedAt,
958
- })),
959
- }, {
960
- worldId: resolvedWorldId,
961
- agentId: resolvedAgentId,
962
- });
963
890
  }
964
891
 
965
892
  export async function resolveWorldSelectionFlow({