@xfxstudio/claworld 0.1.4 → 0.2.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 (55) hide show
  1. package/README.md +12 -29
  2. package/openclaw.plugin.json +9 -33
  3. package/package.json +2 -10
  4. package/skills/claworld-help/SKILL.md +86 -160
  5. package/skills/claworld-join-and-chat/SKILL.md +107 -203
  6. package/skills/claworld-manage-worlds/SKILL.md +75 -392
  7. package/src/lib/chat-request.js +347 -0
  8. package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
  9. package/src/openclaw/index.js +0 -5
  10. package/src/openclaw/installer/cli.js +14 -16
  11. package/src/openclaw/installer/core.js +13 -14
  12. package/src/openclaw/installer/doctor.js +69 -31
  13. package/src/openclaw/installer/workspace-contract.js +33 -9
  14. package/src/openclaw/plugin/claworld-channel-plugin.js +156 -625
  15. package/src/openclaw/plugin/config-schema.js +4 -16
  16. package/src/openclaw/plugin/managed-config.js +127 -75
  17. package/src/openclaw/plugin/onboarding.js +7 -3
  18. package/src/openclaw/plugin/register.js +40 -339
  19. package/src/openclaw/plugin/relay-client.js +112 -102
  20. package/src/openclaw/protocol/relay-event-protocol.js +34 -22
  21. package/src/openclaw/runtime/canonical-result-builder.js +15 -5
  22. package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
  23. package/src/openclaw/runtime/feedback-helper.js +3 -2
  24. package/src/openclaw/runtime/inbound-session-router.js +28 -20
  25. package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
  26. package/src/openclaw/runtime/product-shell-helper.js +45 -637
  27. package/src/openclaw/runtime/runtime-path.js +2 -2
  28. package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
  29. package/src/openclaw/runtime/tool-contracts.js +36 -258
  30. package/src/openclaw/runtime/world-moderation-helper.js +11 -65
  31. package/src/product-shell/catalog/default-world-catalog.js +15 -33
  32. package/src/product-shell/contracts/candidate-feed.js +40 -5
  33. package/src/product-shell/contracts/chat-request-approval-policy.js +3 -3
  34. package/src/product-shell/contracts/world-manifest.js +134 -161
  35. package/src/product-shell/contracts/world-orchestration.js +55 -326
  36. package/src/product-shell/feedback/feedback-routes.js +4 -3
  37. package/src/product-shell/feedback/feedback-service.js +11 -8
  38. package/src/product-shell/index.js +6 -7
  39. package/src/product-shell/matching/matchmaking-service.js +39 -5
  40. package/src/product-shell/membership/membership-service.js +125 -147
  41. package/src/product-shell/onboarding/onboarding-service.js +2 -2
  42. package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
  43. package/src/product-shell/orchestration/world-conversation-text.js +231 -0
  44. package/src/product-shell/results/result-service.js +9 -3
  45. package/src/product-shell/search/search-service.js +28 -1
  46. package/src/product-shell/social/chat-request-routes.js +0 -1
  47. package/src/product-shell/social/chat-request-service.js +1 -102
  48. package/src/product-shell/worlds/world-admin-service.js +86 -277
  49. package/src/product-shell/worlds/world-authorization.js +3 -5
  50. package/src/product-shell/worlds/world-routes.js +8 -38
  51. package/src/product-shell/worlds/world-service.js +3 -3
  52. package/src/product-shell/worlds/world-text.js +77 -0
  53. package/src/lib/runtime-guidance.js +0 -457
  54. package/src/openclaw/runtime/world-session-startup.js +0 -1
  55. package/src/product-shell/orchestration/session-orchestrator.js +0 -38
@@ -3,10 +3,6 @@ import { buildRuntimeAuthHeaders } from '../plugin/account-identity.js';
3
3
  import { createRuntimeBoundaryError } from '../../lib/runtime-errors.js';
4
4
  import {
5
5
  buildCandidateDeliverySummary as buildBackendCandidateDeliverySummary,
6
- buildResolvedWorldJoinOrchestration as buildBackendResolvedWorldJoinOrchestration,
7
- buildWorldJoinOutcomeOrchestration as buildBackendWorldJoinOutcomeOrchestration,
8
- buildRequiredFieldExplanation as buildBackendRequiredFieldExplanation,
9
- buildWorldProfileCollectionFlow as buildBackendWorldProfileCollectionFlow,
10
6
  buildWorldSelectionPrompt as buildBackendWorldSelectionPrompt,
11
7
  resolveWorldSelection as resolveBackendWorldSelection,
12
8
  } from '../../product-shell/contracts/world-orchestration.js';
@@ -75,13 +71,6 @@ function normalizeProfile(profile = {}) {
75
71
  );
76
72
  }
77
73
 
78
- function mergeProfileState(profile = {}, profileUpdate = {}) {
79
- return {
80
- ...normalizeProfile(profile),
81
- ...normalizeProfile(profileUpdate),
82
- };
83
- }
84
-
85
74
  function normalizeLookupText(value) {
86
75
  return normalizeText(value, '')?.toLowerCase() || '';
87
76
  }
@@ -115,12 +104,9 @@ function normalizeWorldSummary(world = {}) {
115
104
  return {
116
105
  worldId: normalizeText(rawWorldId, 'unknown-world'),
117
106
  displayName: normalizeText(summary.displayName || world.displayName, normalizeText(rawWorldId, 'Unknown World')),
118
- summary: normalizeText(summary.summary || world.summary, ''),
119
- category: normalizeText(summary.category || world.category, 'general'),
107
+ worldContextText: normalizeText(summary.worldContextText || world.worldContextText, ''),
120
108
  hotness: normalizeInteger(summary.hotness || world.hotness || world.activatedMemberCount, 0),
121
109
  requiredFieldCount: normalizeInteger(summary.requiredFieldCount || world.requiredFieldCount, 0),
122
- matchingMode: normalizeText(summary.matchingMode || world.matchingMode, 'manual_review'),
123
- sessionMode: normalizeText(summary.sessionMode || world.sessionMode, 'a2a'),
124
110
  };
125
111
  }
126
112
 
@@ -138,6 +124,22 @@ function normalizeField(field = {}, index = 0, { required = false } = {}) {
138
124
  };
139
125
  }
140
126
 
127
+ function buildParticipantContextField(field = null) {
128
+ if (field && typeof field === 'object' && !Array.isArray(field)) {
129
+ return normalizeField(field, 0, { required: true });
130
+ }
131
+ return normalizeField({
132
+ fieldId: 'participantContextText',
133
+ label: 'Entry Profile',
134
+ type: 'string',
135
+ source: 'membership',
136
+ required: true,
137
+ description: 'A short text describing who you are in this world and what context you bring into it.',
138
+ examples: [],
139
+ constraints: {},
140
+ }, 0, { required: true });
141
+ }
142
+
141
143
  function normalizeSearchSchema(payload = {}, { worldId = null, fallbackFields = [] } = {}) {
142
144
  const rawInputFields = Array.isArray(payload.inputFields) && payload.inputFields.length > 0
143
145
  ? payload.inputFields
@@ -181,33 +183,15 @@ function normalizeWorldDetail(payload = {}) {
181
183
  source: normalizeText(payload.source, 'product_shell'),
182
184
  worldId: normalizedWorldId,
183
185
  displayName: normalizeText(payload.displayName, normalizedWorldId),
184
- summary: normalizeText(payload.summary, ''),
185
- description: normalizeText(payload.description, normalizeText(payload.summary, '')),
186
- category: normalizeText(payload.category, 'general'),
186
+ worldContextText: normalizeText(payload.worldContextText, ''),
187
+ ownerAgentId: normalizeText(payload.ownerAgentId, null),
188
+ enabled: typeof payload.enabled === 'boolean' ? payload.enabled : null,
187
189
  requiredFieldCount: normalizeInteger(payload.requiredFieldCount, requiredFields.length) || requiredFields.length,
188
190
  optionalFieldCount: normalizeInteger(payload.optionalFieldCount, optionalFields.length) || optionalFields.length,
189
- matchingMode: normalizeText(payload.matchingMode, 'manual_review'),
190
- sessionMode: normalizeText(payload.sessionMode, 'a2a'),
191
- interactionRules: normalizeText(payload.interactionRules, null),
192
- prohibitedRules: normalizeText(payload.prohibitedRules, null),
193
- ratingRules: normalizeText(payload.ratingRules, null),
194
- adminAgentIds: normalizeStringList(payload.adminAgentIds),
195
- eligibility: normalizeText(payload.eligibility, 'active'),
196
- broadcast: normalizeBroadcastConfig(payload.broadcast),
197
191
  requiredFields,
198
192
  optionalFields,
199
193
  hints: normalizeStringList(payload.hints),
200
194
  nextAction: normalizeText(payload.nextAction, 'call_join_world'),
201
- sessionOverview: payload.sessionOverview && typeof payload.sessionOverview === 'object' ? payload.sessionOverview : {},
202
- matchingOverview: payload.matchingOverview && typeof payload.matchingOverview === 'object' ? payload.matchingOverview : {},
203
- requiredFieldExplanation:
204
- payload.requiredFieldExplanation && typeof payload.requiredFieldExplanation === 'object'
205
- ? payload.requiredFieldExplanation
206
- : null,
207
- runtimeStartupContext:
208
- payload.runtimeStartupContext && typeof payload.runtimeStartupContext === 'object'
209
- ? payload.runtimeStartupContext
210
- : null,
211
195
  searchSchema: normalizeSearchSchema(payload.searchSchema || {}, {
212
196
  worldId: normalizedWorldId,
213
197
  fallbackFields: requiredFields,
@@ -216,63 +200,39 @@ function normalizeWorldDetail(payload = {}) {
216
200
  }
217
201
 
218
202
  const world = payload.world && typeof payload.world === 'object' ? payload.world : {};
219
- const agentSummary = payload.agentSummary && typeof payload.agentSummary === 'object' ? payload.agentSummary : {};
203
+ const management = payload.management && typeof payload.management === 'object' ? payload.management : {};
220
204
  const joinSchema = payload.joinSchema && typeof payload.joinSchema === 'object' ? payload.joinSchema : {};
221
205
  const fieldGuide = payload.fieldGuide && typeof payload.fieldGuide === 'object' ? payload.fieldGuide : {};
222
- const sessionOverview = payload.sessionOverview && typeof payload.sessionOverview === 'object'
223
- ? payload.sessionOverview
224
- : {};
225
- const matchingOverview = payload.matchingOverview && typeof payload.matchingOverview === 'object'
226
- ? payload.matchingOverview
227
- : {};
228
206
  const searchOverview = payload.searchSchema && typeof payload.searchSchema === 'object'
229
207
  ? payload.searchSchema
230
208
  : {};
209
+ const participantContextField = buildParticipantContextField(
210
+ payload.participantContextField
211
+ || (Array.isArray(fieldGuide.required) ? fieldGuide.required[0] : null)
212
+ || (Array.isArray(joinSchema.requiredFields) ? joinSchema.requiredFields[0] : null),
213
+ );
231
214
 
232
- const requiredInput = Array.isArray(fieldGuide.required) && fieldGuide.required.length > 0
233
- ? fieldGuide.required
234
- : (Array.isArray(joinSchema.requiredFields) ? joinSchema.requiredFields : []);
235
- const optionalInput = Array.isArray(fieldGuide.optional) && fieldGuide.optional.length > 0
236
- ? fieldGuide.optional
237
- : (Array.isArray(joinSchema.optionalFields) ? joinSchema.optionalFields : []);
238
-
239
- const requiredFields = requiredInput.map((field, index) => normalizeField(field, index, { required: true }));
240
- const optionalFields = optionalInput.map((field, index) => normalizeField(field, index, { required: false }));
215
+ const requiredFields = [participantContextField];
216
+ const optionalFields = [];
241
217
  const worldId = normalizeText(world.worldId || joinSchema.worldId, 'unknown-world');
242
- const displayName = normalizeText(agentSummary.displayName || world.displayName, worldId);
218
+ const displayName = normalizeText(world.displayName, worldId);
243
219
 
244
220
  return {
245
221
  status: 'ready',
246
222
  source: 'product_shell',
247
223
  worldId,
248
224
  displayName,
249
- summary: normalizeText(agentSummary.summary || world.summary, ''),
250
- description: normalizeText(world.description, normalizeText(agentSummary.summary || world.summary, '')),
251
- category: normalizeText(agentSummary.category || world.category, 'general'),
252
- requiredFieldCount: normalizeInteger(joinSchema.requiredFieldCount, requiredFields.length) || requiredFields.length,
253
- optionalFieldCount: normalizeInteger(joinSchema.optionalFieldCount, optionalFields.length) || optionalFields.length,
254
- matchingMode: normalizeText(agentSummary.matchingMode || matchingOverview.mode || world.matching?.mode, 'manual_review'),
255
- sessionMode: normalizeText(agentSummary.sessionMode || sessionOverview.mode || world.sessionTemplate?.mode, 'a2a'),
256
- interactionRules: normalizeText(world.interactionRules, null),
257
- prohibitedRules: normalizeText(world.prohibitedRules, null),
258
- ratingRules: normalizeText(world.ratingRules, null),
259
- adminAgentIds: normalizeStringList(world.adminAgentIds),
260
- eligibility: normalizeText(world.eligibility, 'active'),
261
- broadcast: normalizeBroadcastConfig(world.broadcast),
225
+ worldContextText: normalizeText(world.worldContextText || payload.worldContextText, ''),
226
+ ownerAgentId: normalizeText(management.ownerAgentId, null),
227
+ enabled: typeof management.enabled === 'boolean' ? management.enabled : null,
228
+ statusLabel: normalizeText(management.status, null),
229
+ requiredFieldCount: 1,
230
+ optionalFieldCount: 0,
262
231
  requiredFields,
263
232
  optionalFields,
264
- hints: normalizeStringList(joinSchema.hints),
233
+ participantContextField,
234
+ hints: [],
265
235
  nextAction: normalizeText(joinSchema.nextAction, 'call_join_world'),
266
- sessionOverview,
267
- matchingOverview,
268
- requiredFieldExplanation:
269
- payload.requiredFieldExplanation && typeof payload.requiredFieldExplanation === 'object'
270
- ? payload.requiredFieldExplanation
271
- : null,
272
- runtimeStartupContext:
273
- payload.runtimeStartupContext && typeof payload.runtimeStartupContext === 'object'
274
- ? payload.runtimeStartupContext
275
- : null,
276
236
  searchSchema: normalizeSearchSchema(searchOverview, {
277
237
  worldId,
278
238
  fallbackFields: [...requiredFields, ...optionalFields],
@@ -280,59 +240,6 @@ function normalizeWorldDetail(payload = {}) {
280
240
  };
281
241
  }
282
242
 
283
- function normalizeJoinCheckField(field = {}, index = 0) {
284
- return normalizeField(field, index, { required: true });
285
- }
286
-
287
- function normalizeJoinCheckResponse(payload = {}, { worldId = null, profile = {} } = {}) {
288
- const missingFields = Array.isArray(payload.missingFields)
289
- ? payload.missingFields.map((field, index) => normalizeJoinCheckField(field, index))
290
- : [];
291
- const guidance = payload.missingFieldGuidance && typeof payload.missingFieldGuidance === 'object'
292
- ? payload.missingFieldGuidance
293
- : {};
294
- const orderedMissingFields = Array.isArray(guidance.orderedMissingFields)
295
- ? guidance.orderedMissingFields.map((field, index) => normalizeJoinCheckField(field, index))
296
- : missingFields;
297
- const fallbackNextMissingField = orderedMissingFields[0] || missingFields[0] || null;
298
- const nextMissingField = payload.nextMissingField
299
- ? normalizeJoinCheckField(payload.nextMissingField)
300
- : (guidance.nextMissingField ? normalizeJoinCheckField(guidance.nextMissingField) : fallbackNextMissingField);
301
- const accepted = payload.accepted === true || orderedMissingFields.length === 0;
302
-
303
- return {
304
- worldId: normalizeText(payload.worldId, worldId || 'unknown-world'),
305
- accepted,
306
- status: normalizeText(payload.status, accepted ? 'eligible' : 'needs_profile'),
307
- missingFields,
308
- nextMissingField,
309
- missingFieldGuidance: {
310
- mode: normalizeText(guidance.mode, nextMissingField ? 'ordered_required_fields' : 'complete'),
311
- orderedMissingFields,
312
- orderedMissingFieldIds: normalizeStringList(
313
- Array.isArray(guidance.orderedMissingFieldIds)
314
- ? guidance.orderedMissingFieldIds
315
- : orderedMissingFields.map((field) => field.fieldId),
316
- ),
317
- nextMissingField,
318
- remainingRequiredFieldCount: normalizeInteger(guidance.remainingRequiredFieldCount, orderedMissingFields.length),
319
- },
320
- normalizedProfile: normalizeProfile(
321
- payload.normalizedProfile && typeof payload.normalizedProfile === 'object'
322
- ? payload.normalizedProfile
323
- : profile,
324
- ),
325
- nextAction: normalizeText(
326
- payload.nextAction,
327
- accepted ? 'call_join_world' : 'retry_join_world_after_profile_update',
328
- ),
329
- profileCollectionFlow:
330
- payload.profileCollectionFlow && typeof payload.profileCollectionFlow === 'object'
331
- ? payload.profileCollectionFlow
332
- : null,
333
- };
334
- }
335
-
336
243
  function normalizeNumber(value, fallback = null) {
337
244
  const parsed = Number(value);
338
245
  if (!Number.isFinite(parsed)) return fallback;
@@ -422,6 +329,7 @@ function normalizeCandidate(candidate = {}, index = 0) {
422
329
  worldId: normalizeText(candidate.worldId, 'unknown-world'),
423
330
  targetAgentId: normalizeText(candidate.targetAgentId, null),
424
331
  sourceMembershipId: normalizeText(candidate.sourceMembershipId, null),
332
+ online: candidate.online === true,
425
333
  targetAgentId,
426
334
  requestChat,
427
335
  profileSummary: normalizeCandidateProfileSummary(candidate.profileSummary),
@@ -457,7 +365,7 @@ function normalizeCandidateFeedResponse(payload = {}, { worldId = null, agentId
457
365
  candidateDelivery: payload.candidateDelivery && typeof payload.candidateDelivery === 'object'
458
366
  ? payload.candidateDelivery
459
367
  : null,
460
- candidateSource: normalizeText(payload.candidateSource, 'active_memberships'),
368
+ candidateSource: normalizeText(payload.candidateSource, 'active_memberships_online'),
461
369
  candidateModel: payload.candidateModel && typeof payload.candidateModel === 'object' ? payload.candidateModel : {},
462
370
  strategy: payload.strategy && typeof payload.strategy === 'object' ? payload.strategy : {},
463
371
  limit: normalizeInteger(payload.limit, candidates.length),
@@ -508,50 +416,6 @@ function normalizeWorldJoinResponse(payload = {}, { worldId = null, agentId = nu
508
416
  };
509
417
  }
510
418
 
511
- function projectMissingRequiredFields(fields = []) {
512
- return fields.map((field) => ({
513
- fieldId: field.fieldId,
514
- label: field.label,
515
- description: field.description || null,
516
- }));
517
- }
518
-
519
- function buildJoinRequestBody({ agentId = null, profile = {}, profileSnapshot = null } = {}) {
520
- const normalizedAgentId = normalizeText(agentId, null);
521
- const normalizedProfile = normalizeProfile(profile);
522
- const normalizedProfileSnapshot = normalizeProfile(profileSnapshot);
523
-
524
- return {
525
- agentId: normalizedAgentId,
526
- ...(Object.keys(normalizedProfileSnapshot).length > 0
527
- ? { profileSnapshot: normalizedProfileSnapshot }
528
- : (Object.keys(normalizedProfile).length > 0 ? { profile: normalizedProfile } : {})),
529
- };
530
- }
531
-
532
- function resolveJoinSubmissionProfile({
533
- profile = {},
534
- profileSnapshot = null,
535
- profileUpdate = null,
536
- profilePatch = null,
537
- } = {}) {
538
- const normalizedProfile = normalizeProfile(profile);
539
- const normalizedProfileSnapshot = normalizeProfile(profileSnapshot);
540
- const appliedProfileUpdate = normalizeProfile(profileUpdate || profilePatch || {});
541
- const baseProfile = Object.keys(normalizedProfileSnapshot).length > 0
542
- ? normalizedProfileSnapshot
543
- : normalizedProfile;
544
-
545
- return {
546
- baseProfile,
547
- appliedProfileUpdate,
548
- mergedProfile: mergeProfileState(baseProfile, appliedProfileUpdate),
549
- preferProfileSnapshot:
550
- Object.keys(normalizedProfileSnapshot).length > 0
551
- || Object.keys(appliedProfileUpdate).length > 0,
552
- };
553
- }
554
-
555
419
  function normalizeSearchMatchedField(field = {}, index = 0) {
556
420
  return {
557
421
  fieldId: normalizeText(field.fieldId, `field_${index + 1}`),
@@ -647,71 +511,6 @@ export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail
647
511
  return buildBackendCandidateDeliverySummary(candidateFeed, { worldDetail, limit });
648
512
  }
649
513
 
650
- function buildFieldLookup(worldDetail = {}) {
651
- const detail = normalizeWorldDetail(worldDetail);
652
- return new Map(
653
- [...detail.requiredFields, ...detail.optionalFields].map((field) => [field.fieldId, field]),
654
- );
655
- }
656
-
657
- function selectPromptFields(joinCheck = {}, worldDetail = {}, maxFieldsPerStep = 1) {
658
- if (joinCheck.accepted) return [];
659
-
660
- const fieldLookup = buildFieldLookup(worldDetail);
661
- const orderedMissingFields = Array.isArray(joinCheck.missingFieldGuidance?.orderedMissingFields)
662
- && joinCheck.missingFieldGuidance.orderedMissingFields.length > 0
663
- ? joinCheck.missingFieldGuidance.orderedMissingFields
664
- : (Array.isArray(joinCheck.missingFields) ? joinCheck.missingFields : []);
665
-
666
- return orderedMissingFields.slice(0, Math.max(1, maxFieldsPerStep)).map((field, index) => {
667
- const detailField = fieldLookup.get(field.fieldId) || {};
668
- return normalizeField(
669
- {
670
- ...detailField,
671
- ...field,
672
- description: normalizeText(field.description, detailField.description || null),
673
- examples: Array.isArray(detailField.examples) ? detailField.examples : field.examples,
674
- constraints: detailField.constraints || field.constraints,
675
- },
676
- index,
677
- { required: true },
678
- );
679
- });
680
- }
681
-
682
- function buildProfileFieldPrompt(field = {}, index = 0, total = 1) {
683
- const examples = Array.isArray(field.examples) && field.examples.length > 0
684
- ? ` Example: ${field.examples.map((example) => quoteExample(example)).join(' or ')}.`
685
- : '';
686
- const description = sentenceCase(
687
- field.description || `Provide ${field.label} so the world can evaluate the profile`,
688
- 'Provide this field so the world can evaluate the profile.',
689
- );
690
- const prefix = total > 1 ? `${index + 1}. ` : '';
691
-
692
- return `${prefix}${field.label}. ${description}${examples}`;
693
- }
694
-
695
- function listProvidedRequiredFieldIds(worldDetail = {}, profile = {}, missingFieldIds = []) {
696
- const missingSet = new Set(normalizeStringList(missingFieldIds));
697
- return normalizeWorldDetail(worldDetail).requiredFields
698
- .filter((field) => !missingSet.has(field.fieldId) && !isEmptyProfileValue(profile[field.fieldId]))
699
- .map((field) => field.fieldId);
700
- }
701
-
702
- function buildProfileCollectionFollowUp(promptFields = []) {
703
- if (promptFields.length === 0) {
704
- return 'The current profile is already eligible. Continue with the next world step without restarting profile collection.';
705
- }
706
-
707
- const labels = promptFields.map((field) => field.label);
708
- if (promptFields.length === 1) {
709
- return `After the user answers ${labels[0]}, merge it into the saved profile draft and retry join_world before asking anything else.`;
710
- }
711
-
712
- return `After the user answers ${joinAsNaturalLanguage(labels)}, merge those fields into the saved profile draft and retry join_world before asking anything else.`;
713
- }
714
-
715
514
  function normalizeSelectionInput(selection) {
716
515
  if (selection && typeof selection === 'object') {
717
516
  const asWorldId = normalizeText(selection.worldId, null);
@@ -983,67 +782,13 @@ export async function fetchWorldDetail({
983
782
  return normalizeWorldDetail(detail.body);
984
783
  }
985
784
 
986
- export async function fetchWorldJoinCheck({
987
- cfg = {},
988
- accountId = null,
989
- runtimeConfig = null,
990
- worldId = null,
991
- profile = {},
992
- maxFieldsPerStep = null,
993
- fetchImpl,
994
- logger = console,
995
- } = {}) {
996
- if (typeof fetchImpl !== 'function') {
997
- throw new Error('fetch is unavailable for claworld product-shell join-check helper');
998
- }
999
-
1000
- const resolvedWorldId = normalizeText(worldId, null);
1001
- if (!resolvedWorldId) {
1002
- throw new Error('claworld product-shell join-check helper requires worldId');
1003
- }
1004
-
1005
- const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1006
- const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1007
- const normalizedProfile = normalizeProfile(profile);
1008
- const joinCheck = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join-check`, {
1009
- method: 'POST',
1010
- headers: {
1011
- accept: 'application/json',
1012
- 'content-type': 'application/json',
1013
- ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1014
- ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1015
- },
1016
- body: JSON.stringify({
1017
- profile: normalizedProfile,
1018
- ...(maxFieldsPerStep == null ? {} : { maxFieldsPerStep }),
1019
- }),
1020
- });
1021
-
1022
- if (!joinCheck.ok && joinCheck.status !== 422) {
1023
- logger.error?.('[claworld:product-shell] world join-check failed', {
1024
- status: joinCheck.status,
1025
- worldId: resolvedWorldId,
1026
- accountId: resolvedRuntimeConfig.accountId || accountId || null,
1027
- body: joinCheck.body,
1028
- });
1029
- throw new Error(`claworld product-shell join-check failed: ${joinCheck.status}`);
1030
- }
1031
-
1032
- return normalizeJoinCheckResponse(joinCheck.body, {
1033
- worldId: resolvedWorldId,
1034
- profile: normalizedProfile,
1035
- });
1036
- }
1037
-
1038
785
  export async function joinWorld({
1039
786
  cfg = {},
1040
787
  accountId = null,
1041
788
  runtimeConfig = null,
1042
789
  worldId = null,
1043
790
  agentId = null,
1044
- profile = {},
1045
- profileSnapshot = null,
1046
- maxFieldsPerStep = null,
791
+ participantContextText = null,
1047
792
  fetchImpl,
1048
793
  logger = console,
1049
794
  } = {}) {
@@ -1063,14 +808,6 @@ export async function joinWorld({
1063
808
 
1064
809
  const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1065
810
  const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1066
- const requestBody = buildJoinRequestBody({
1067
- agentId: resolvedAgentId,
1068
- profile,
1069
- profileSnapshot,
1070
- });
1071
- if (maxFieldsPerStep != null) {
1072
- requestBody.maxFieldsPerStep = maxFieldsPerStep;
1073
- }
1074
811
  const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
1075
812
  method: 'POST',
1076
813
  headers: {
@@ -1079,7 +816,10 @@ export async function joinWorld({
1079
816
  ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1080
817
  ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1081
818
  },
1082
- body: JSON.stringify(requestBody),
819
+ body: JSON.stringify({
820
+ agentId: resolvedAgentId,
821
+ participantContextText: normalizeText(participantContextText, null),
822
+ }),
1083
823
  });
1084
824
 
1085
825
  if (!joinResult.ok) {
@@ -1099,143 +839,6 @@ export async function joinWorld({
1099
839
  });
1100
840
  }
1101
841
 
1102
- export async function submitWorldJoin({
1103
- cfg = {},
1104
- accountId = null,
1105
- runtimeConfig = null,
1106
- worldId = null,
1107
- agentId = null,
1108
- profile = {},
1109
- profileSnapshot = null,
1110
- profileUpdate = null,
1111
- profilePatch = null,
1112
- worldDetail = null,
1113
- maxFieldsPerStep = 1,
1114
- fetchImpl,
1115
- logger = console,
1116
- } = {}) {
1117
- if (typeof fetchImpl !== 'function') {
1118
- throw new Error('fetch is unavailable for claworld product-shell join helper');
1119
- }
1120
-
1121
- const resolvedWorldId = normalizeText(worldId, null);
1122
- if (!resolvedWorldId) {
1123
- throw new Error('claworld product-shell join helper requires worldId');
1124
- }
1125
-
1126
- const resolvedAgentId = normalizeText(agentId, null);
1127
- if (!resolvedAgentId) {
1128
- throw new Error('claworld product-shell join helper requires agentId');
1129
- }
1130
-
1131
- const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1132
- const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1133
- const joinProfile = resolveJoinSubmissionProfile({
1134
- profile,
1135
- profileSnapshot,
1136
- profileUpdate,
1137
- profilePatch,
1138
- });
1139
- const requestBody = buildJoinRequestBody({
1140
- agentId: resolvedAgentId,
1141
- profile: joinProfile.mergedProfile,
1142
- profileSnapshot: joinProfile.preferProfileSnapshot ? joinProfile.mergedProfile : null,
1143
- });
1144
- if (maxFieldsPerStep != null) {
1145
- requestBody.maxFieldsPerStep = maxFieldsPerStep;
1146
- }
1147
- const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
1148
- method: 'POST',
1149
- headers: {
1150
- accept: 'application/json',
1151
- 'content-type': 'application/json',
1152
- ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1153
- ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1154
- },
1155
- body: JSON.stringify(requestBody),
1156
- });
1157
-
1158
- if (!joinResult.ok && joinResult.status !== 422) {
1159
- logger.error?.('[claworld:product-shell] world join failed', {
1160
- status: joinResult.status,
1161
- worldId: resolvedWorldId,
1162
- agentId: resolvedAgentId,
1163
- accountId: resolvedRuntimeConfig.accountId || accountId || null,
1164
- body: joinResult.body,
1165
- });
1166
- throw new Error(`claworld product-shell world join failed: ${joinResult.status}`);
1167
- }
1168
-
1169
- if (joinResult.status === 422) {
1170
- const detail = worldDetail
1171
- ? normalizeWorldDetail(worldDetail)
1172
- : await fetchWorldDetail({
1173
- cfg,
1174
- accountId,
1175
- runtimeConfig: resolvedRuntimeConfig,
1176
- worldId: resolvedWorldId,
1177
- fetchImpl,
1178
- logger,
1179
- });
1180
- const joinCheck = normalizeJoinCheckResponse(joinResult.body, {
1181
- worldId: resolvedWorldId,
1182
- profile: joinProfile.mergedProfile,
1183
- });
1184
- const profileCollectionFlow = {
1185
- ...buildBackendWorldProfileCollectionFlow({
1186
- worldDetail: detail,
1187
- joinCheck,
1188
- profile: joinCheck.normalizedProfile,
1189
- maxFieldsPerStep,
1190
- }),
1191
- worldDetail: detail,
1192
- joinCheck,
1193
- profile: joinCheck.normalizedProfile,
1194
- appliedProfileUpdate: joinProfile.appliedProfileUpdate,
1195
- };
1196
-
1197
- return {
1198
- status: 'needs_profile',
1199
- worldId: resolvedWorldId,
1200
- agentId: resolvedAgentId,
1201
- membershipStatus: normalizeText(joinResult.body?.membershipStatus, 'inactive'),
1202
- normalizedProfile: profileCollectionFlow.profile,
1203
- missingFields: projectMissingRequiredFields(joinCheck.missingFields),
1204
- nextMissingField: joinCheck.nextMissingField
1205
- ? projectMissingRequiredFields([joinCheck.nextMissingField])[0]
1206
- : null,
1207
- nextAction: normalizeText(joinResult.body?.nextAction, 'retry_join_world_after_profile_update'),
1208
- missingFieldGuidance: joinCheck.missingFieldGuidance,
1209
- candidateFeed: null,
1210
- candidateDelivery: null,
1211
- joinCheck,
1212
- profileCollectionFlow,
1213
- profileDraft: profileCollectionFlow.profile,
1214
- missingRequiredFields: projectMissingRequiredFields(joinCheck.missingFields),
1215
- orchestration: null,
1216
- };
1217
- }
1218
-
1219
- const normalizedJoinResult = normalizeWorldJoinResponse(joinResult.body, {
1220
- worldId: resolvedWorldId,
1221
- agentId: resolvedAgentId,
1222
- });
1223
-
1224
- return {
1225
- status: normalizedJoinResult.status,
1226
- worldId: normalizedJoinResult.worldId,
1227
- agentId: normalizedJoinResult.agentId,
1228
- membershipStatus: normalizedJoinResult.membershipStatus,
1229
- normalizedProfile: normalizedJoinResult.normalizedProfile,
1230
- membership: normalizedJoinResult.membership,
1231
- nextAction: normalizedJoinResult.nextAction,
1232
- nextStageSummary: normalizedJoinResult.nextStageSummary,
1233
- candidateFeed: normalizedJoinResult.candidateFeed,
1234
- candidateDelivery: normalizedJoinResult.candidateDelivery,
1235
- orchestration: normalizedJoinResult.orchestration || null,
1236
- };
1237
- }
1238
-
1239
842
  export async function fetchWorldSearch({
1240
843
  cfg = {},
1241
844
  accountId = null,
@@ -1501,89 +1104,6 @@ export async function fetchWorldCandidateFeed({
1501
1104
  });
1502
1105
  }
1503
1106
 
1504
- function buildFieldStepPrompt(field = {}, index = 0, total = 1) {
1505
- const examples = Array.isArray(field.examples) && field.examples.length > 0
1506
- ? ` Example: ${field.examples.map((example) => quoteExample(example)).join(' or ')}.`
1507
- : '';
1508
- const description = sentenceCase(
1509
- field.description || `Provide ${field.label} so the world can evaluate the profile`,
1510
- 'Provide this field so the world can evaluate the profile.',
1511
- );
1512
-
1513
- return `Step ${index + 1} of ${total}: ${field.label}. ${description}${examples}`;
1514
- }
1515
-
1516
- export function buildRequiredFieldExplanation(worldDetail = {}) {
1517
- if (worldDetail?.requiredFieldExplanation && typeof worldDetail.requiredFieldExplanation === 'object') {
1518
- return worldDetail.requiredFieldExplanation;
1519
- }
1520
- // Compatibility fallback for older world-detail payloads that do not yet
1521
- // carry backend-authored required-field explanation.
1522
- return buildBackendRequiredFieldExplanation(worldDetail);
1523
- }
1524
-
1525
- export async function resolveWorldProfileCollectionFlow({
1526
- cfg = {},
1527
- accountId = null,
1528
- runtimeConfig = null,
1529
- worldId = null,
1530
- worldDetail = null,
1531
- profile = {},
1532
- profileUpdate = null,
1533
- profilePatch = null,
1534
- maxFieldsPerStep = 1,
1535
- fetchImpl,
1536
- logger = console,
1537
- } = {}) {
1538
- const appliedProfileUpdate = normalizeProfile(profileUpdate || profilePatch || {});
1539
- const mergedProfile = mergeProfileState(profile, appliedProfileUpdate);
1540
- const detail = worldDetail
1541
- ? normalizeWorldDetail(worldDetail)
1542
- : await fetchWorldDetail({
1543
- cfg,
1544
- accountId,
1545
- runtimeConfig,
1546
- worldId,
1547
- fetchImpl,
1548
- logger,
1549
- });
1550
- const resolvedWorldId = normalizeText(worldId || detail.worldId, detail.worldId);
1551
- if (!resolvedWorldId) {
1552
- throw new Error('claworld product-shell profile collection flow requires worldId');
1553
- }
1554
-
1555
- const joinCheck = await fetchWorldJoinCheck({
1556
- cfg,
1557
- accountId,
1558
- runtimeConfig,
1559
- worldId: resolvedWorldId,
1560
- profile: mergedProfile,
1561
- maxFieldsPerStep,
1562
- fetchImpl,
1563
- logger,
1564
- });
1565
- const backendFlow = joinCheck.profileCollectionFlow && typeof joinCheck.profileCollectionFlow === 'object'
1566
- ? joinCheck.profileCollectionFlow
1567
- : buildBackendWorldProfileCollectionFlow({
1568
- worldDetail: detail,
1569
- joinCheck,
1570
- profile: joinCheck.normalizedProfile,
1571
- maxFieldsPerStep,
1572
- });
1573
-
1574
- return {
1575
- ...backendFlow,
1576
- appliedProfileUpdate,
1577
- worldDetail: detail,
1578
- joinCheck,
1579
- worldId: resolvedWorldId,
1580
- displayName: detail.displayName,
1581
- profile: joinCheck.normalizedProfile,
1582
- accepted: joinCheck.accepted,
1583
- status: joinCheck.status,
1584
- };
1585
- }
1586
-
1587
1107
  export async function resolveWorldSelectionFlow({
1588
1108
  cfg = {},
1589
1109
  accountId = null,
@@ -1591,7 +1111,6 @@ export async function resolveWorldSelectionFlow({
1591
1111
  worldDirectory = null,
1592
1112
  selection = null,
1593
1113
  profile = {},
1594
- maxFieldsPerStep = 1,
1595
1114
  fetchImpl,
1596
1115
  logger = console,
1597
1116
  } = {}) {
@@ -1641,19 +1160,6 @@ export async function resolveWorldSelectionFlow({
1641
1160
  fetchImpl,
1642
1161
  logger,
1643
1162
  });
1644
- const requiredFieldExplanation = buildRequiredFieldExplanation(worldDetail);
1645
- const profileCollectionFlow = await resolveWorldProfileCollectionFlow({
1646
- cfg,
1647
- accountId,
1648
- runtimeConfig,
1649
- worldId: resolvedSelection.selectedWorld.worldId,
1650
- worldDetail,
1651
- profile,
1652
- maxFieldsPerStep,
1653
- fetchImpl,
1654
- logger,
1655
- });
1656
-
1657
1163
  return {
1658
1164
  status: 'selected',
1659
1165
  source: 'product_shell',
@@ -1661,105 +1167,7 @@ export async function resolveWorldSelectionFlow({
1661
1167
  selection: resolvedSelection.selection,
1662
1168
  selectedWorld: resolvedSelection.selectedWorld,
1663
1169
  worldDetail,
1664
- requiredFieldExplanation,
1665
- profileCollectionFlow,
1170
+ participantContextField: worldDetail.participantContextField || null,
1666
1171
  orchestration: resolvedSelection.orchestration || null,
1667
1172
  };
1668
1173
  }
1669
-
1670
- export async function resolveWorldJoinFlow({
1671
- cfg = {},
1672
- accountId = null,
1673
- runtimeConfig = null,
1674
- worldId = null,
1675
- worldDetail = null,
1676
- agentId = null,
1677
- profile = {},
1678
- profileSnapshot = null,
1679
- profileUpdate = null,
1680
- profilePatch = null,
1681
- maxFieldsPerStep = 1,
1682
- limit = null,
1683
- fetchImpl,
1684
- logger = console,
1685
- } = {}) {
1686
- const detail = worldDetail
1687
- ? normalizeWorldDetail(worldDetail)
1688
- : await fetchWorldDetail({
1689
- cfg,
1690
- accountId,
1691
- runtimeConfig,
1692
- worldId,
1693
- fetchImpl,
1694
- logger,
1695
- });
1696
- const resolvedWorldId = normalizeText(worldId || detail.worldId, detail.worldId);
1697
- if (!resolvedWorldId) {
1698
- throw new Error('claworld product-shell join flow requires worldId');
1699
- }
1700
-
1701
- const joinResult = await submitWorldJoin({
1702
- cfg,
1703
- accountId,
1704
- runtimeConfig,
1705
- worldId: resolvedWorldId,
1706
- agentId,
1707
- profile,
1708
- profileSnapshot,
1709
- profileUpdate,
1710
- profilePatch,
1711
- maxFieldsPerStep,
1712
- fetchImpl,
1713
- logger,
1714
- });
1715
- if (joinResult.status === 'needs_profile') {
1716
- return joinResult;
1717
- }
1718
- const candidateFeed = limit == null && joinResult.candidateFeed
1719
- ? joinResult.candidateFeed
1720
- : await fetchWorldCandidateFeed({
1721
- cfg,
1722
- accountId,
1723
- runtimeConfig,
1724
- worldId: resolvedWorldId,
1725
- agentId: joinResult.agentId || agentId,
1726
- limit,
1727
- fetchImpl,
1728
- logger,
1729
- });
1730
- const candidateDelivery = joinResult.candidateDelivery || buildCandidateDeliverySummary(candidateFeed, {
1731
- worldDetail: detail,
1732
- limit,
1733
- });
1734
- const joinOrchestration = joinResult.orchestration && typeof joinResult.orchestration === 'object'
1735
- ? joinResult.orchestration
1736
- : buildBackendWorldJoinOutcomeOrchestration({
1737
- worldDetail: detail,
1738
- joinResult,
1739
- });
1740
-
1741
- return {
1742
- status: candidateDelivery.status,
1743
- source: 'product_shell',
1744
- worldId: resolvedWorldId,
1745
- displayName: detail.displayName,
1746
- agentId: joinResult.agentId || normalizeText(agentId, null),
1747
- worldDetail: detail,
1748
- membershipStatus: joinResult.membershipStatus,
1749
- normalizedProfile: joinResult.normalizedProfile,
1750
- membership: joinResult.membership,
1751
- nextAction: normalizeText(joinResult.nextAction, candidateDelivery.nextAction),
1752
- nextStageSummary: joinResult.nextStageSummary,
1753
- joinResult,
1754
- candidateFeed,
1755
- candidateDelivery,
1756
- requestChatAction: candidateDelivery.requestChatAction,
1757
- orchestration: buildBackendResolvedWorldJoinOrchestration({
1758
- joinResult: {
1759
- ...joinResult,
1760
- orchestration: joinOrchestration,
1761
- },
1762
- candidateDelivery,
1763
- }),
1764
- };
1765
- }