@xfxstudio/claworld 0.1.5 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +12 -29
  2. package/openclaw.plugin.json +5 -29
  3. package/package.json +4 -12
  4. package/skills/claworld-help/SKILL.md +50 -182
  5. package/skills/claworld-join-and-chat/SKILL.md +78 -288
  6. package/skills/claworld-manage-worlds/SKILL.md +71 -288
  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 +18 -9
  11. package/src/openclaw/installer/core.js +12 -6
  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 +118 -623
  15. package/src/openclaw/plugin/config-schema.js +3 -15
  16. package/src/openclaw/plugin/managed-config.js +98 -47
  17. package/src/openclaw/plugin/onboarding.js +7 -3
  18. package/src/openclaw/plugin/register.js +37 -336
  19. package/src/openclaw/plugin/relay-client.js +111 -101
  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 +43 -636
  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 +33 -258
  30. package/src/openclaw/runtime/world-moderation-helper.js +11 -65
  31. package/src/product-shell/catalog/default-world-catalog.js +9 -27
  32. package/src/product-shell/contracts/candidate-feed.js +26 -1
  33. package/src/product-shell/contracts/chat-request-approval-policy.js +4 -4
  34. package/src/product-shell/contracts/world-manifest.js +115 -160
  35. package/src/product-shell/contracts/world-orchestration.js +47 -322
  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 +5 -6
  39. package/src/product-shell/membership/membership-service.js +125 -147
  40. package/src/product-shell/onboarding/onboarding-service.js +2 -2
  41. package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
  42. package/src/product-shell/orchestration/world-conversation-text.js +231 -0
  43. package/src/product-shell/results/result-service.js +9 -3
  44. package/src/product-shell/search/search-service.js +28 -1
  45. package/src/product-shell/social/chat-request-routes.js +0 -1
  46. package/src/product-shell/social/chat-request-service.js +1 -102
  47. package/src/product-shell/worlds/world-admin-service.js +85 -276
  48. package/src/product-shell/worlds/world-authorization.js +3 -5
  49. package/src/product-shell/worlds/world-routes.js +8 -38
  50. package/src/product-shell/worlds/world-service.js +3 -3
  51. package/src/product-shell/worlds/world-text.js +77 -0
  52. package/src/lib/runtime-guidance.js +0 -457
  53. package/src/openclaw/runtime/world-session-startup.js +0 -1
  54. 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;
@@ -509,50 +416,6 @@ function normalizeWorldJoinResponse(payload = {}, { worldId = null, agentId = nu
509
416
  };
510
417
  }
511
418
 
512
- function projectMissingRequiredFields(fields = []) {
513
- return fields.map((field) => ({
514
- fieldId: field.fieldId,
515
- label: field.label,
516
- description: field.description || null,
517
- }));
518
- }
519
-
520
- function buildJoinRequestBody({ agentId = null, profile = {}, profileSnapshot = null } = {}) {
521
- const normalizedAgentId = normalizeText(agentId, null);
522
- const normalizedProfile = normalizeProfile(profile);
523
- const normalizedProfileSnapshot = normalizeProfile(profileSnapshot);
524
-
525
- return {
526
- agentId: normalizedAgentId,
527
- ...(Object.keys(normalizedProfileSnapshot).length > 0
528
- ? { profileSnapshot: normalizedProfileSnapshot }
529
- : (Object.keys(normalizedProfile).length > 0 ? { profile: normalizedProfile } : {})),
530
- };
531
- }
532
-
533
- function resolveJoinSubmissionProfile({
534
- profile = {},
535
- profileSnapshot = null,
536
- profileUpdate = null,
537
- profilePatch = null,
538
- } = {}) {
539
- const normalizedProfile = normalizeProfile(profile);
540
- const normalizedProfileSnapshot = normalizeProfile(profileSnapshot);
541
- const appliedProfileUpdate = normalizeProfile(profileUpdate || profilePatch || {});
542
- const baseProfile = Object.keys(normalizedProfileSnapshot).length > 0
543
- ? normalizedProfileSnapshot
544
- : normalizedProfile;
545
-
546
- return {
547
- baseProfile,
548
- appliedProfileUpdate,
549
- mergedProfile: mergeProfileState(baseProfile, appliedProfileUpdate),
550
- preferProfileSnapshot:
551
- Object.keys(normalizedProfileSnapshot).length > 0
552
- || Object.keys(appliedProfileUpdate).length > 0,
553
- };
554
- }
555
-
556
419
  function normalizeSearchMatchedField(field = {}, index = 0) {
557
420
  return {
558
421
  fieldId: normalizeText(field.fieldId, `field_${index + 1}`),
@@ -648,71 +511,6 @@ export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail
648
511
  return buildBackendCandidateDeliverySummary(candidateFeed, { worldDetail, limit });
649
512
  }
650
513
 
651
- function buildFieldLookup(worldDetail = {}) {
652
- const detail = normalizeWorldDetail(worldDetail);
653
- return new Map(
654
- [...detail.requiredFields, ...detail.optionalFields].map((field) => [field.fieldId, field]),
655
- );
656
- }
657
-
658
- function selectPromptFields(joinCheck = {}, worldDetail = {}, maxFieldsPerStep = 1) {
659
- if (joinCheck.accepted) return [];
660
-
661
- const fieldLookup = buildFieldLookup(worldDetail);
662
- const orderedMissingFields = Array.isArray(joinCheck.missingFieldGuidance?.orderedMissingFields)
663
- && joinCheck.missingFieldGuidance.orderedMissingFields.length > 0
664
- ? joinCheck.missingFieldGuidance.orderedMissingFields
665
- : (Array.isArray(joinCheck.missingFields) ? joinCheck.missingFields : []);
666
-
667
- return orderedMissingFields.slice(0, Math.max(1, maxFieldsPerStep)).map((field, index) => {
668
- const detailField = fieldLookup.get(field.fieldId) || {};
669
- return normalizeField(
670
- {
671
- ...detailField,
672
- ...field,
673
- description: normalizeText(field.description, detailField.description || null),
674
- examples: Array.isArray(detailField.examples) ? detailField.examples : field.examples,
675
- constraints: detailField.constraints || field.constraints,
676
- },
677
- index,
678
- { required: true },
679
- );
680
- });
681
- }
682
-
683
- function buildProfileFieldPrompt(field = {}, index = 0, total = 1) {
684
- const examples = Array.isArray(field.examples) && field.examples.length > 0
685
- ? ` Example: ${field.examples.map((example) => quoteExample(example)).join(' or ')}.`
686
- : '';
687
- const description = sentenceCase(
688
- field.description || `Provide ${field.label} so the world can evaluate the profile`,
689
- 'Provide this field so the world can evaluate the profile.',
690
- );
691
- const prefix = total > 1 ? `${index + 1}. ` : '';
692
-
693
- return `${prefix}${field.label}. ${description}${examples}`;
694
- }
695
-
696
- function listProvidedRequiredFieldIds(worldDetail = {}, profile = {}, missingFieldIds = []) {
697
- const missingSet = new Set(normalizeStringList(missingFieldIds));
698
- return normalizeWorldDetail(worldDetail).requiredFields
699
- .filter((field) => !missingSet.has(field.fieldId) && !isEmptyProfileValue(profile[field.fieldId]))
700
- .map((field) => field.fieldId);
701
- }
702
-
703
- function buildProfileCollectionFollowUp(promptFields = []) {
704
- if (promptFields.length === 0) {
705
- return 'The current profile is already eligible. Continue with the next world step without restarting profile collection.';
706
- }
707
-
708
- const labels = promptFields.map((field) => field.label);
709
- if (promptFields.length === 1) {
710
- return `After the user answers ${labels[0]}, merge it into the saved profile draft and retry join_world before asking anything else.`;
711
- }
712
-
713
- return `After the user answers ${joinAsNaturalLanguage(labels)}, merge those fields into the saved profile draft and retry join_world before asking anything else.`;
714
- }
715
-
716
514
  function normalizeSelectionInput(selection) {
717
515
  if (selection && typeof selection === 'object') {
718
516
  const asWorldId = normalizeText(selection.worldId, null);
@@ -984,67 +782,13 @@ export async function fetchWorldDetail({
984
782
  return normalizeWorldDetail(detail.body);
985
783
  }
986
784
 
987
- export async function fetchWorldJoinCheck({
988
- cfg = {},
989
- accountId = null,
990
- runtimeConfig = null,
991
- worldId = null,
992
- profile = {},
993
- maxFieldsPerStep = null,
994
- fetchImpl,
995
- logger = console,
996
- } = {}) {
997
- if (typeof fetchImpl !== 'function') {
998
- throw new Error('fetch is unavailable for claworld product-shell join-check helper');
999
- }
1000
-
1001
- const resolvedWorldId = normalizeText(worldId, null);
1002
- if (!resolvedWorldId) {
1003
- throw new Error('claworld product-shell join-check helper requires worldId');
1004
- }
1005
-
1006
- const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1007
- const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1008
- const normalizedProfile = normalizeProfile(profile);
1009
- const joinCheck = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join-check`, {
1010
- method: 'POST',
1011
- headers: {
1012
- accept: 'application/json',
1013
- 'content-type': 'application/json',
1014
- ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1015
- ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1016
- },
1017
- body: JSON.stringify({
1018
- profile: normalizedProfile,
1019
- ...(maxFieldsPerStep == null ? {} : { maxFieldsPerStep }),
1020
- }),
1021
- });
1022
-
1023
- if (!joinCheck.ok && joinCheck.status !== 422) {
1024
- logger.error?.('[claworld:product-shell] world join-check failed', {
1025
- status: joinCheck.status,
1026
- worldId: resolvedWorldId,
1027
- accountId: resolvedRuntimeConfig.accountId || accountId || null,
1028
- body: joinCheck.body,
1029
- });
1030
- throw new Error(`claworld product-shell join-check failed: ${joinCheck.status}`);
1031
- }
1032
-
1033
- return normalizeJoinCheckResponse(joinCheck.body, {
1034
- worldId: resolvedWorldId,
1035
- profile: normalizedProfile,
1036
- });
1037
- }
1038
-
1039
785
  export async function joinWorld({
1040
786
  cfg = {},
1041
787
  accountId = null,
1042
788
  runtimeConfig = null,
1043
789
  worldId = null,
1044
790
  agentId = null,
1045
- profile = {},
1046
- profileSnapshot = null,
1047
- maxFieldsPerStep = null,
791
+ participantContextText = null,
1048
792
  fetchImpl,
1049
793
  logger = console,
1050
794
  } = {}) {
@@ -1064,14 +808,6 @@ export async function joinWorld({
1064
808
 
1065
809
  const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1066
810
  const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1067
- const requestBody = buildJoinRequestBody({
1068
- agentId: resolvedAgentId,
1069
- profile,
1070
- profileSnapshot,
1071
- });
1072
- if (maxFieldsPerStep != null) {
1073
- requestBody.maxFieldsPerStep = maxFieldsPerStep;
1074
- }
1075
811
  const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
1076
812
  method: 'POST',
1077
813
  headers: {
@@ -1080,7 +816,10 @@ export async function joinWorld({
1080
816
  ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1081
817
  ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1082
818
  },
1083
- body: JSON.stringify(requestBody),
819
+ body: JSON.stringify({
820
+ agentId: resolvedAgentId,
821
+ participantContextText: normalizeText(participantContextText, null),
822
+ }),
1084
823
  });
1085
824
 
1086
825
  if (!joinResult.ok) {
@@ -1100,143 +839,6 @@ export async function joinWorld({
1100
839
  });
1101
840
  }
1102
841
 
1103
- export async function submitWorldJoin({
1104
- cfg = {},
1105
- accountId = null,
1106
- runtimeConfig = null,
1107
- worldId = null,
1108
- agentId = null,
1109
- profile = {},
1110
- profileSnapshot = null,
1111
- profileUpdate = null,
1112
- profilePatch = null,
1113
- worldDetail = null,
1114
- maxFieldsPerStep = 1,
1115
- fetchImpl,
1116
- logger = console,
1117
- } = {}) {
1118
- if (typeof fetchImpl !== 'function') {
1119
- throw new Error('fetch is unavailable for claworld product-shell join helper');
1120
- }
1121
-
1122
- const resolvedWorldId = normalizeText(worldId, null);
1123
- if (!resolvedWorldId) {
1124
- throw new Error('claworld product-shell join helper requires worldId');
1125
- }
1126
-
1127
- const resolvedAgentId = normalizeText(agentId, null);
1128
- if (!resolvedAgentId) {
1129
- throw new Error('claworld product-shell join helper requires agentId');
1130
- }
1131
-
1132
- const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
1133
- const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
1134
- const joinProfile = resolveJoinSubmissionProfile({
1135
- profile,
1136
- profileSnapshot,
1137
- profileUpdate,
1138
- profilePatch,
1139
- });
1140
- const requestBody = buildJoinRequestBody({
1141
- agentId: resolvedAgentId,
1142
- profile: joinProfile.mergedProfile,
1143
- profileSnapshot: joinProfile.preferProfileSnapshot ? joinProfile.mergedProfile : null,
1144
- });
1145
- if (maxFieldsPerStep != null) {
1146
- requestBody.maxFieldsPerStep = maxFieldsPerStep;
1147
- }
1148
- const joinResult = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/join`, {
1149
- method: 'POST',
1150
- headers: {
1151
- accept: 'application/json',
1152
- 'content-type': 'application/json',
1153
- ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
1154
- ...(resolvedRuntimeConfig.relay?.credentialToken ? { 'x-relay-token': resolvedRuntimeConfig.relay.credentialToken } : {}),
1155
- },
1156
- body: JSON.stringify(requestBody),
1157
- });
1158
-
1159
- if (!joinResult.ok && joinResult.status !== 422) {
1160
- logger.error?.('[claworld:product-shell] world join failed', {
1161
- status: joinResult.status,
1162
- worldId: resolvedWorldId,
1163
- agentId: resolvedAgentId,
1164
- accountId: resolvedRuntimeConfig.accountId || accountId || null,
1165
- body: joinResult.body,
1166
- });
1167
- throw new Error(`claworld product-shell world join failed: ${joinResult.status}`);
1168
- }
1169
-
1170
- if (joinResult.status === 422) {
1171
- const detail = worldDetail
1172
- ? normalizeWorldDetail(worldDetail)
1173
- : await fetchWorldDetail({
1174
- cfg,
1175
- accountId,
1176
- runtimeConfig: resolvedRuntimeConfig,
1177
- worldId: resolvedWorldId,
1178
- fetchImpl,
1179
- logger,
1180
- });
1181
- const joinCheck = normalizeJoinCheckResponse(joinResult.body, {
1182
- worldId: resolvedWorldId,
1183
- profile: joinProfile.mergedProfile,
1184
- });
1185
- const profileCollectionFlow = {
1186
- ...buildBackendWorldProfileCollectionFlow({
1187
- worldDetail: detail,
1188
- joinCheck,
1189
- profile: joinCheck.normalizedProfile,
1190
- maxFieldsPerStep,
1191
- }),
1192
- worldDetail: detail,
1193
- joinCheck,
1194
- profile: joinCheck.normalizedProfile,
1195
- appliedProfileUpdate: joinProfile.appliedProfileUpdate,
1196
- };
1197
-
1198
- return {
1199
- status: 'needs_profile',
1200
- worldId: resolvedWorldId,
1201
- agentId: resolvedAgentId,
1202
- membershipStatus: normalizeText(joinResult.body?.membershipStatus, 'inactive'),
1203
- normalizedProfile: profileCollectionFlow.profile,
1204
- missingFields: projectMissingRequiredFields(joinCheck.missingFields),
1205
- nextMissingField: joinCheck.nextMissingField
1206
- ? projectMissingRequiredFields([joinCheck.nextMissingField])[0]
1207
- : null,
1208
- nextAction: normalizeText(joinResult.body?.nextAction, 'retry_join_world_after_profile_update'),
1209
- missingFieldGuidance: joinCheck.missingFieldGuidance,
1210
- candidateFeed: null,
1211
- candidateDelivery: null,
1212
- joinCheck,
1213
- profileCollectionFlow,
1214
- profileDraft: profileCollectionFlow.profile,
1215
- missingRequiredFields: projectMissingRequiredFields(joinCheck.missingFields),
1216
- orchestration: null,
1217
- };
1218
- }
1219
-
1220
- const normalizedJoinResult = normalizeWorldJoinResponse(joinResult.body, {
1221
- worldId: resolvedWorldId,
1222
- agentId: resolvedAgentId,
1223
- });
1224
-
1225
- return {
1226
- status: normalizedJoinResult.status,
1227
- worldId: normalizedJoinResult.worldId,
1228
- agentId: normalizedJoinResult.agentId,
1229
- membershipStatus: normalizedJoinResult.membershipStatus,
1230
- normalizedProfile: normalizedJoinResult.normalizedProfile,
1231
- membership: normalizedJoinResult.membership,
1232
- nextAction: normalizedJoinResult.nextAction,
1233
- nextStageSummary: normalizedJoinResult.nextStageSummary,
1234
- candidateFeed: normalizedJoinResult.candidateFeed,
1235
- candidateDelivery: normalizedJoinResult.candidateDelivery,
1236
- orchestration: normalizedJoinResult.orchestration || null,
1237
- };
1238
- }
1239
-
1240
842
  export async function fetchWorldSearch({
1241
843
  cfg = {},
1242
844
  accountId = null,
@@ -1502,89 +1104,6 @@ export async function fetchWorldCandidateFeed({
1502
1104
  });
1503
1105
  }
1504
1106
 
1505
- function buildFieldStepPrompt(field = {}, index = 0, total = 1) {
1506
- const examples = Array.isArray(field.examples) && field.examples.length > 0
1507
- ? ` Example: ${field.examples.map((example) => quoteExample(example)).join(' or ')}.`
1508
- : '';
1509
- const description = sentenceCase(
1510
- field.description || `Provide ${field.label} so the world can evaluate the profile`,
1511
- 'Provide this field so the world can evaluate the profile.',
1512
- );
1513
-
1514
- return `Step ${index + 1} of ${total}: ${field.label}. ${description}${examples}`;
1515
- }
1516
-
1517
- export function buildRequiredFieldExplanation(worldDetail = {}) {
1518
- if (worldDetail?.requiredFieldExplanation && typeof worldDetail.requiredFieldExplanation === 'object') {
1519
- return worldDetail.requiredFieldExplanation;
1520
- }
1521
- // Compatibility fallback for older world-detail payloads that do not yet
1522
- // carry backend-authored required-field explanation.
1523
- return buildBackendRequiredFieldExplanation(worldDetail);
1524
- }
1525
-
1526
- export async function resolveWorldProfileCollectionFlow({
1527
- cfg = {},
1528
- accountId = null,
1529
- runtimeConfig = null,
1530
- worldId = null,
1531
- worldDetail = null,
1532
- profile = {},
1533
- profileUpdate = null,
1534
- profilePatch = null,
1535
- maxFieldsPerStep = 1,
1536
- fetchImpl,
1537
- logger = console,
1538
- } = {}) {
1539
- const appliedProfileUpdate = normalizeProfile(profileUpdate || profilePatch || {});
1540
- const mergedProfile = mergeProfileState(profile, appliedProfileUpdate);
1541
- const detail = worldDetail
1542
- ? normalizeWorldDetail(worldDetail)
1543
- : await fetchWorldDetail({
1544
- cfg,
1545
- accountId,
1546
- runtimeConfig,
1547
- worldId,
1548
- fetchImpl,
1549
- logger,
1550
- });
1551
- const resolvedWorldId = normalizeText(worldId || detail.worldId, detail.worldId);
1552
- if (!resolvedWorldId) {
1553
- throw new Error('claworld product-shell profile collection flow requires worldId');
1554
- }
1555
-
1556
- const joinCheck = await fetchWorldJoinCheck({
1557
- cfg,
1558
- accountId,
1559
- runtimeConfig,
1560
- worldId: resolvedWorldId,
1561
- profile: mergedProfile,
1562
- maxFieldsPerStep,
1563
- fetchImpl,
1564
- logger,
1565
- });
1566
- const backendFlow = joinCheck.profileCollectionFlow && typeof joinCheck.profileCollectionFlow === 'object'
1567
- ? joinCheck.profileCollectionFlow
1568
- : buildBackendWorldProfileCollectionFlow({
1569
- worldDetail: detail,
1570
- joinCheck,
1571
- profile: joinCheck.normalizedProfile,
1572
- maxFieldsPerStep,
1573
- });
1574
-
1575
- return {
1576
- ...backendFlow,
1577
- appliedProfileUpdate,
1578
- worldDetail: detail,
1579
- joinCheck,
1580
- worldId: resolvedWorldId,
1581
- displayName: detail.displayName,
1582
- profile: joinCheck.normalizedProfile,
1583
- accepted: joinCheck.accepted,
1584
- status: joinCheck.status,
1585
- };
1586
- }
1587
-
1588
1107
  export async function resolveWorldSelectionFlow({
1589
1108
  cfg = {},
1590
1109
  accountId = null,
@@ -1592,7 +1111,6 @@ export async function resolveWorldSelectionFlow({
1592
1111
  worldDirectory = null,
1593
1112
  selection = null,
1594
1113
  profile = {},
1595
- maxFieldsPerStep = 1,
1596
1114
  fetchImpl,
1597
1115
  logger = console,
1598
1116
  } = {}) {
@@ -1642,19 +1160,6 @@ export async function resolveWorldSelectionFlow({
1642
1160
  fetchImpl,
1643
1161
  logger,
1644
1162
  });
1645
- const requiredFieldExplanation = buildRequiredFieldExplanation(worldDetail);
1646
- const profileCollectionFlow = await resolveWorldProfileCollectionFlow({
1647
- cfg,
1648
- accountId,
1649
- runtimeConfig,
1650
- worldId: resolvedSelection.selectedWorld.worldId,
1651
- worldDetail,
1652
- profile,
1653
- maxFieldsPerStep,
1654
- fetchImpl,
1655
- logger,
1656
- });
1657
-
1658
1163
  return {
1659
1164
  status: 'selected',
1660
1165
  source: 'product_shell',
@@ -1662,105 +1167,7 @@ export async function resolveWorldSelectionFlow({
1662
1167
  selection: resolvedSelection.selection,
1663
1168
  selectedWorld: resolvedSelection.selectedWorld,
1664
1169
  worldDetail,
1665
- requiredFieldExplanation,
1666
- profileCollectionFlow,
1170
+ participantContextField: worldDetail.participantContextField || null,
1667
1171
  orchestration: resolvedSelection.orchestration || null,
1668
1172
  };
1669
1173
  }
1670
-
1671
- export async function resolveWorldJoinFlow({
1672
- cfg = {},
1673
- accountId = null,
1674
- runtimeConfig = null,
1675
- worldId = null,
1676
- worldDetail = null,
1677
- agentId = null,
1678
- profile = {},
1679
- profileSnapshot = null,
1680
- profileUpdate = null,
1681
- profilePatch = null,
1682
- maxFieldsPerStep = 1,
1683
- limit = null,
1684
- fetchImpl,
1685
- logger = console,
1686
- } = {}) {
1687
- const detail = worldDetail
1688
- ? normalizeWorldDetail(worldDetail)
1689
- : await fetchWorldDetail({
1690
- cfg,
1691
- accountId,
1692
- runtimeConfig,
1693
- worldId,
1694
- fetchImpl,
1695
- logger,
1696
- });
1697
- const resolvedWorldId = normalizeText(worldId || detail.worldId, detail.worldId);
1698
- if (!resolvedWorldId) {
1699
- throw new Error('claworld product-shell join flow requires worldId');
1700
- }
1701
-
1702
- const joinResult = await submitWorldJoin({
1703
- cfg,
1704
- accountId,
1705
- runtimeConfig,
1706
- worldId: resolvedWorldId,
1707
- agentId,
1708
- profile,
1709
- profileSnapshot,
1710
- profileUpdate,
1711
- profilePatch,
1712
- maxFieldsPerStep,
1713
- fetchImpl,
1714
- logger,
1715
- });
1716
- if (joinResult.status === 'needs_profile') {
1717
- return joinResult;
1718
- }
1719
- const candidateFeed = limit == null && joinResult.candidateFeed
1720
- ? joinResult.candidateFeed
1721
- : await fetchWorldCandidateFeed({
1722
- cfg,
1723
- accountId,
1724
- runtimeConfig,
1725
- worldId: resolvedWorldId,
1726
- agentId: joinResult.agentId || agentId,
1727
- limit,
1728
- fetchImpl,
1729
- logger,
1730
- });
1731
- const candidateDelivery = joinResult.candidateDelivery || buildCandidateDeliverySummary(candidateFeed, {
1732
- worldDetail: detail,
1733
- limit,
1734
- });
1735
- const joinOrchestration = joinResult.orchestration && typeof joinResult.orchestration === 'object'
1736
- ? joinResult.orchestration
1737
- : buildBackendWorldJoinOutcomeOrchestration({
1738
- worldDetail: detail,
1739
- joinResult,
1740
- });
1741
-
1742
- return {
1743
- status: candidateDelivery.status,
1744
- source: 'product_shell',
1745
- worldId: resolvedWorldId,
1746
- displayName: detail.displayName,
1747
- agentId: joinResult.agentId || normalizeText(agentId, null),
1748
- worldDetail: detail,
1749
- membershipStatus: joinResult.membershipStatus,
1750
- normalizedProfile: joinResult.normalizedProfile,
1751
- membership: joinResult.membership,
1752
- nextAction: normalizeText(joinResult.nextAction, candidateDelivery.nextAction),
1753
- nextStageSummary: joinResult.nextStageSummary,
1754
- joinResult,
1755
- candidateFeed,
1756
- candidateDelivery,
1757
- requestChatAction: candidateDelivery.requestChatAction,
1758
- orchestration: buildBackendResolvedWorldJoinOrchestration({
1759
- joinResult: {
1760
- ...joinResult,
1761
- orchestration: joinOrchestration,
1762
- },
1763
- candidateDelivery,
1764
- }),
1765
- };
1766
- }