@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.
- package/README.md +12 -29
- package/openclaw.plugin.json +5 -29
- package/package.json +4 -12
- package/skills/claworld-help/SKILL.md +50 -182
- package/skills/claworld-join-and-chat/SKILL.md +78 -288
- package/skills/claworld-manage-worlds/SKILL.md +71 -288
- package/src/lib/chat-request.js +347 -0
- package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
- package/src/openclaw/index.js +0 -5
- package/src/openclaw/installer/cli.js +18 -9
- package/src/openclaw/installer/core.js +12 -6
- package/src/openclaw/installer/doctor.js +69 -31
- package/src/openclaw/installer/workspace-contract.js +33 -9
- package/src/openclaw/plugin/claworld-channel-plugin.js +118 -623
- package/src/openclaw/plugin/config-schema.js +3 -15
- package/src/openclaw/plugin/managed-config.js +98 -47
- package/src/openclaw/plugin/onboarding.js +7 -3
- package/src/openclaw/plugin/register.js +37 -336
- package/src/openclaw/plugin/relay-client.js +111 -101
- package/src/openclaw/protocol/relay-event-protocol.js +34 -22
- package/src/openclaw/runtime/canonical-result-builder.js +15 -5
- package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
- package/src/openclaw/runtime/feedback-helper.js +3 -2
- package/src/openclaw/runtime/inbound-session-router.js +28 -20
- package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
- package/src/openclaw/runtime/product-shell-helper.js +43 -636
- package/src/openclaw/runtime/runtime-path.js +2 -2
- package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
- package/src/openclaw/runtime/tool-contracts.js +33 -258
- package/src/openclaw/runtime/world-moderation-helper.js +11 -65
- package/src/product-shell/catalog/default-world-catalog.js +9 -27
- package/src/product-shell/contracts/candidate-feed.js +26 -1
- package/src/product-shell/contracts/chat-request-approval-policy.js +4 -4
- package/src/product-shell/contracts/world-manifest.js +115 -160
- package/src/product-shell/contracts/world-orchestration.js +47 -322
- package/src/product-shell/feedback/feedback-routes.js +4 -3
- package/src/product-shell/feedback/feedback-service.js +11 -8
- package/src/product-shell/index.js +5 -6
- package/src/product-shell/membership/membership-service.js +125 -147
- package/src/product-shell/onboarding/onboarding-service.js +2 -2
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
- package/src/product-shell/orchestration/world-conversation-text.js +231 -0
- package/src/product-shell/results/result-service.js +9 -3
- package/src/product-shell/search/search-service.js +28 -1
- package/src/product-shell/social/chat-request-routes.js +0 -1
- package/src/product-shell/social/chat-request-service.js +1 -102
- package/src/product-shell/worlds/world-admin-service.js +85 -276
- package/src/product-shell/worlds/world-authorization.js +3 -5
- package/src/product-shell/worlds/world-routes.js +8 -38
- package/src/product-shell/worlds/world-service.js +3 -3
- package/src/product-shell/worlds/world-text.js +77 -0
- package/src/lib/runtime-guidance.js +0 -457
- package/src/openclaw/runtime/world-session-startup.js +0 -1
- package/src/product-shell/orchestration/session-orchestrator.js +0 -38
|
@@ -68,13 +68,6 @@ export function normalizeProfile(profile = {}) {
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export function mergeProfileState(profile = {}, profileUpdate = {}) {
|
|
72
|
-
return {
|
|
73
|
-
...normalizeProfile(profile),
|
|
74
|
-
...normalizeProfile(profileUpdate),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
71
|
function normalizeLookupText(value) {
|
|
79
72
|
return normalizeText(value, '')?.toLowerCase() || '';
|
|
80
73
|
}
|
|
@@ -108,12 +101,9 @@ function normalizeWorldSummary(world = {}) {
|
|
|
108
101
|
return {
|
|
109
102
|
worldId: normalizeText(rawWorldId, 'unknown-world'),
|
|
110
103
|
displayName: normalizeText(summary.displayName || world.displayName, normalizeText(rawWorldId, 'Unknown World')),
|
|
111
|
-
|
|
112
|
-
category: normalizeText(summary.category || world.category, 'general'),
|
|
104
|
+
worldContextText: normalizeText(summary.worldContextText || world.worldContextText, ''),
|
|
113
105
|
hotness: normalizeInteger(summary.hotness || world.hotness || world.activatedMemberCount, 0),
|
|
114
106
|
requiredFieldCount: normalizeInteger(summary.requiredFieldCount || world.requiredFieldCount, 0),
|
|
115
|
-
matchingMode: normalizeText(summary.matchingMode || world.matchingMode, 'manual_review'),
|
|
116
|
-
sessionMode: normalizeText(summary.sessionMode || world.sessionMode, 'a2a'),
|
|
117
107
|
};
|
|
118
108
|
}
|
|
119
109
|
|
|
@@ -180,7 +170,7 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
180
170
|
requiredFieldCount: normalizeInteger(payload.requiredFieldCount, requiredFields.length) || requiredFields.length,
|
|
181
171
|
optionalFieldCount: normalizeInteger(payload.optionalFieldCount, optionalFields.length) || optionalFields.length,
|
|
182
172
|
matchingMode: normalizeText(payload.matchingMode, 'manual_review'),
|
|
183
|
-
|
|
173
|
+
conversationMode: normalizeText(payload.conversationMode, 'a2a'),
|
|
184
174
|
interactionRules: normalizeText(payload.interactionRules, null),
|
|
185
175
|
prohibitedRules: normalizeText(payload.prohibitedRules, null),
|
|
186
176
|
ratingRules: normalizeText(payload.ratingRules, null),
|
|
@@ -191,7 +181,10 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
191
181
|
optionalFields,
|
|
192
182
|
hints: normalizeStringList(payload.hints),
|
|
193
183
|
nextAction: normalizeText(payload.nextAction, 'call_join_world'),
|
|
194
|
-
|
|
184
|
+
conversationOverview:
|
|
185
|
+
payload.conversationOverview && typeof payload.conversationOverview === 'object'
|
|
186
|
+
? payload.conversationOverview
|
|
187
|
+
: {},
|
|
195
188
|
matchingOverview: payload.matchingOverview && typeof payload.matchingOverview === 'object' ? payload.matchingOverview : {},
|
|
196
189
|
searchSchema: normalizeSearchSchema(payload.searchSchema || {}, {
|
|
197
190
|
worldId: normalizedWorldId,
|
|
@@ -204,8 +197,8 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
204
197
|
const agentSummary = payload.agentSummary && typeof payload.agentSummary === 'object' ? payload.agentSummary : {};
|
|
205
198
|
const joinSchema = payload.joinSchema && typeof payload.joinSchema === 'object' ? payload.joinSchema : {};
|
|
206
199
|
const fieldGuide = payload.fieldGuide && typeof payload.fieldGuide === 'object' ? payload.fieldGuide : {};
|
|
207
|
-
const
|
|
208
|
-
? payload.
|
|
200
|
+
const conversationOverview = payload.conversationOverview && typeof payload.conversationOverview === 'object'
|
|
201
|
+
? payload.conversationOverview
|
|
209
202
|
: {};
|
|
210
203
|
const matchingOverview = payload.matchingOverview && typeof payload.matchingOverview === 'object'
|
|
211
204
|
? payload.matchingOverview
|
|
@@ -237,7 +230,10 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
237
230
|
requiredFieldCount: normalizeInteger(joinSchema.requiredFieldCount, requiredFields.length) || requiredFields.length,
|
|
238
231
|
optionalFieldCount: normalizeInteger(joinSchema.optionalFieldCount, optionalFields.length) || optionalFields.length,
|
|
239
232
|
matchingMode: normalizeText(payload.matchingMode || agentSummary.matchingMode || matchingOverview.mode || world.matching?.mode, 'manual_review'),
|
|
240
|
-
|
|
233
|
+
conversationMode: normalizeText(
|
|
234
|
+
payload.conversationMode || agentSummary.conversationMode || conversationOverview.mode || world.conversationTemplate?.mode,
|
|
235
|
+
'a2a',
|
|
236
|
+
),
|
|
241
237
|
interactionRules: normalizeText(payload.interactionRules || world.interactionRules, null),
|
|
242
238
|
prohibitedRules: normalizeText(payload.prohibitedRules || world.prohibitedRules, null),
|
|
243
239
|
ratingRules: normalizeText(payload.ratingRules || world.ratingRules, null),
|
|
@@ -248,7 +244,7 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
248
244
|
optionalFields,
|
|
249
245
|
hints: normalizeStringList(payload.hints || joinSchema.hints),
|
|
250
246
|
nextAction: normalizeText(payload.nextAction || joinSchema.nextAction, 'call_join_world'),
|
|
251
|
-
|
|
247
|
+
conversationOverview,
|
|
252
248
|
matchingOverview,
|
|
253
249
|
searchSchema: normalizeSearchSchema(searchOverview, {
|
|
254
250
|
worldId,
|
|
@@ -257,55 +253,6 @@ function normalizeWorldDetail(payload = {}) {
|
|
|
257
253
|
};
|
|
258
254
|
}
|
|
259
255
|
|
|
260
|
-
function normalizeJoinCheckField(field = {}, index = 0) {
|
|
261
|
-
return normalizeField(field, index, { required: true });
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function normalizeJoinCheckResponse(payload = {}, { worldId = null, profile = {} } = {}) {
|
|
265
|
-
const missingFields = Array.isArray(payload.missingFields)
|
|
266
|
-
? payload.missingFields.map((field, index) => normalizeJoinCheckField(field, index))
|
|
267
|
-
: [];
|
|
268
|
-
const guidance = payload.missingFieldGuidance && typeof payload.missingFieldGuidance === 'object'
|
|
269
|
-
? payload.missingFieldGuidance
|
|
270
|
-
: {};
|
|
271
|
-
const orderedMissingFields = Array.isArray(guidance.orderedMissingFields)
|
|
272
|
-
? guidance.orderedMissingFields.map((field, index) => normalizeJoinCheckField(field, index))
|
|
273
|
-
: missingFields;
|
|
274
|
-
const fallbackNextMissingField = orderedMissingFields[0] || missingFields[0] || null;
|
|
275
|
-
const nextMissingField = payload.nextMissingField
|
|
276
|
-
? normalizeJoinCheckField(payload.nextMissingField)
|
|
277
|
-
: (guidance.nextMissingField ? normalizeJoinCheckField(guidance.nextMissingField) : fallbackNextMissingField);
|
|
278
|
-
const accepted = payload.accepted === true || orderedMissingFields.length === 0;
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
worldId: normalizeText(payload.worldId, worldId || 'unknown-world'),
|
|
282
|
-
accepted,
|
|
283
|
-
status: normalizeText(payload.status, accepted ? 'eligible' : 'needs_profile'),
|
|
284
|
-
missingFields,
|
|
285
|
-
nextMissingField,
|
|
286
|
-
missingFieldGuidance: {
|
|
287
|
-
mode: normalizeText(guidance.mode, nextMissingField ? 'ordered_required_fields' : 'complete'),
|
|
288
|
-
orderedMissingFields,
|
|
289
|
-
orderedMissingFieldIds: normalizeStringList(
|
|
290
|
-
Array.isArray(guidance.orderedMissingFieldIds)
|
|
291
|
-
? guidance.orderedMissingFieldIds
|
|
292
|
-
: orderedMissingFields.map((field) => field.fieldId),
|
|
293
|
-
),
|
|
294
|
-
nextMissingField,
|
|
295
|
-
remainingRequiredFieldCount: normalizeInteger(guidance.remainingRequiredFieldCount, orderedMissingFields.length),
|
|
296
|
-
},
|
|
297
|
-
normalizedProfile: normalizeProfile(
|
|
298
|
-
payload.normalizedProfile && typeof payload.normalizedProfile === 'object'
|
|
299
|
-
? payload.normalizedProfile
|
|
300
|
-
: profile,
|
|
301
|
-
),
|
|
302
|
-
nextAction: normalizeText(
|
|
303
|
-
payload.nextAction,
|
|
304
|
-
accepted ? 'call_join_world' : 'retry_join_world_after_profile_update',
|
|
305
|
-
),
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
|
|
309
256
|
function normalizeProfileSummaryField(field = {}, index = 0) {
|
|
310
257
|
const fieldId = normalizeText(field.fieldId || field.id, `field_${index + 1}`);
|
|
311
258
|
const value = Array.isArray(field.value)
|
|
@@ -450,31 +397,18 @@ function buildCandidateDeliverySummaryLine(candidateSummary = {}, index = 0) {
|
|
|
450
397
|
return `${index + 1}. ${candidateSummary.summary}`;
|
|
451
398
|
}
|
|
452
399
|
|
|
453
|
-
function
|
|
454
|
-
const
|
|
455
|
-
? detail.
|
|
400
|
+
function formatConversationOverview(detail = {}) {
|
|
401
|
+
const conversationOverview = detail.conversationOverview && typeof detail.conversationOverview === 'object'
|
|
402
|
+
? detail.conversationOverview
|
|
456
403
|
: {};
|
|
457
|
-
const mode = normalizeText(detail.
|
|
458
|
-
const maxTurns = normalizeInteger(sessionOverview.maxTurns, null);
|
|
404
|
+
const mode = normalizeText(detail.conversationMode || conversationOverview.mode, null);
|
|
459
405
|
const parts = [];
|
|
460
406
|
|
|
461
407
|
if (mode) parts.push(`${mode} mode`);
|
|
462
|
-
if (maxTurns != null) parts.push(`max ${maxTurns} turns`);
|
|
463
408
|
|
|
464
409
|
return parts.length > 0 ? parts.join(', ') : null;
|
|
465
410
|
}
|
|
466
411
|
|
|
467
|
-
function buildRaiseHandDirective(sessionOverview = {}) {
|
|
468
|
-
const mode = normalizeText(sessionOverview.raiseHandPolicy?.mode, null);
|
|
469
|
-
if (mode === 'dual_raise_hand') {
|
|
470
|
-
return 'When you are ready to conclude, include [[CLAWORLD_RAISE_HAND]] in your reply. The round closes once both agents raise hand.';
|
|
471
|
-
}
|
|
472
|
-
if (mode === 'single_raise_hand' || mode === 'either_raise_hand') {
|
|
473
|
-
return 'When you are ready to conclude, include [[CLAWORLD_RAISE_HAND]] in your reply to close the round.';
|
|
474
|
-
}
|
|
475
|
-
return null;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
412
|
export function buildWorldSessionStartupText(detail = {}) {
|
|
479
413
|
const normalizedDetail = normalizeWorldDetail(detail);
|
|
480
414
|
const worldId = normalizeText(normalizedDetail.worldId, null);
|
|
@@ -482,33 +416,29 @@ export function buildWorldSessionStartupText(detail = {}) {
|
|
|
482
416
|
|
|
483
417
|
const displayName = normalizeText(normalizedDetail.displayName, worldId);
|
|
484
418
|
const summary = normalizeText(normalizedDetail.summary, null);
|
|
485
|
-
const sessionSummary =
|
|
486
|
-
const
|
|
487
|
-
? normalizedDetail.
|
|
419
|
+
const sessionSummary = formatConversationOverview(normalizedDetail);
|
|
420
|
+
const conversationOverview = normalizedDetail.conversationOverview && typeof normalizedDetail.conversationOverview === 'object'
|
|
421
|
+
? normalizedDetail.conversationOverview
|
|
488
422
|
: {};
|
|
489
|
-
const
|
|
490
|
-
const
|
|
491
|
-
const convergenceText = normalizeText(sessionOverview.convergence?.text, null);
|
|
492
|
-
const raiseHandDirective = buildRaiseHandDirective(sessionOverview);
|
|
423
|
+
const openingText = normalizeText(conversationOverview.openingText, null);
|
|
424
|
+
const convergenceText = normalizeText(conversationOverview.convergence?.text, null);
|
|
493
425
|
const interactionRules = normalizeText(normalizedDetail.interactionRules, null);
|
|
494
426
|
const prohibitedRules = normalizeText(normalizedDetail.prohibitedRules, null);
|
|
495
427
|
const ratingRules = normalizeText(normalizedDetail.ratingRules, null);
|
|
496
428
|
|
|
497
429
|
const lines = [
|
|
498
|
-
'Internal Claworld world context for this
|
|
430
|
+
'Internal Claworld world context for this conversation.',
|
|
499
431
|
'Do not acknowledge, paraphrase, or announce this setup to the peer unless it is directly relevant to their message.',
|
|
500
432
|
`World: ${displayName} [${worldId}]`,
|
|
501
433
|
summary ? `Summary: ${summary}` : null,
|
|
502
434
|
sessionSummary ? `Session overview: ${sessionSummary}` : null,
|
|
503
|
-
raiseHandSummary ? `Completion rule: ${raiseHandSummary}` : null,
|
|
504
435
|
'Interruption handling: prefer reconnect/resume. Temporary silence or reconnect churn is not the normal way to close a round.',
|
|
505
436
|
openingText ? `Opening focus: ${openingText}` : null,
|
|
506
437
|
interactionRules ? `Interaction rules: ${interactionRules}` : null,
|
|
507
438
|
prohibitedRules ? `Prohibited rules: ${prohibitedRules}` : null,
|
|
508
439
|
ratingRules ? `Rating rules: ${ratingRules}` : null,
|
|
509
440
|
convergenceText ? `Convergence rule: ${convergenceText}` : null,
|
|
510
|
-
|
|
511
|
-
'Apply these world rules symmetrically when responding in this session.',
|
|
441
|
+
'Apply these world rules symmetrically when responding in this conversation.',
|
|
512
442
|
].filter(Boolean);
|
|
513
443
|
|
|
514
444
|
return lines.join('\n');
|
|
@@ -584,9 +514,8 @@ function buildSelectionRetryContract(status, selection, items = [], matches = []
|
|
|
584
514
|
export function buildWorldSelectionPrompt(worldDirectory = {}) {
|
|
585
515
|
const worldLines = Array.isArray(worldDirectory.items)
|
|
586
516
|
? worldDirectory.items.map((world, index) => (
|
|
587
|
-
`${index + 1}. ${world.displayName} [${world.worldId}]
|
|
588
|
-
+ ` (
|
|
589
|
-
+ ` matching: ${world.matchingMode}; session: ${world.sessionMode})`
|
|
517
|
+
`${index + 1}. ${world.displayName} [${world.worldId}]`
|
|
518
|
+
+ ` (required fields: ${world.requiredFieldCount}; hotness: ${normalizeInteger(world.hotness, 0)})`
|
|
590
519
|
))
|
|
591
520
|
: [];
|
|
592
521
|
|
|
@@ -662,10 +591,10 @@ export function resolveWorldSelection(worldDirectory = {}, selection = null) {
|
|
|
662
591
|
candidateWorlds: items,
|
|
663
592
|
orchestration: {
|
|
664
593
|
stage: 'post_setup_world_selected',
|
|
665
|
-
system: 'Confirm the resolved world choice before fetching detail and
|
|
594
|
+
system: 'Confirm the resolved world choice before fetching detail and collecting participantContextText for join_world.',
|
|
666
595
|
user: `I matched the user choice to ${selectedWorld.displayName} [${selectedWorld.worldId}]. Confirm that this is the world we will use next.`,
|
|
667
596
|
confirmation: `Confirmed world: ${selectedWorld.displayName} [${selectedWorld.worldId}].`,
|
|
668
|
-
followUp: 'Fetch the selected world detail, explain the
|
|
597
|
+
followUp: 'Fetch the selected world detail, explain the participant context requirement, and use join_world once participantContextText is available.',
|
|
669
598
|
},
|
|
670
599
|
};
|
|
671
600
|
}
|
|
@@ -684,246 +613,42 @@ function buildFieldStepPrompt(field = {}, index = 0, total = 1) {
|
|
|
684
613
|
|
|
685
614
|
export function buildRequiredFieldExplanation(worldDetail = {}) {
|
|
686
615
|
const detail = normalizeWorldDetail(worldDetail);
|
|
687
|
-
const
|
|
688
|
-
const
|
|
689
|
-
const
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
constraints: field.constraints,
|
|
702
|
-
}));
|
|
703
|
-
const optionalContextSummary = optionalFieldLabels.length > 0
|
|
704
|
-
? `Optional context you can add later: ${joinAsNaturalLanguage(optionalFieldLabels)}.`
|
|
705
|
-
: null;
|
|
706
|
-
const nextInstruction = steps[0]?.prompt || 'All required fields are already explained. You can move to join_world.';
|
|
616
|
+
const field = detail.requiredFields[0];
|
|
617
|
+
const summary = `To join ${detail.displayName}, I need one ${field.label} text.`;
|
|
618
|
+
const steps = [
|
|
619
|
+
{
|
|
620
|
+
step: 1,
|
|
621
|
+
fieldId: field.fieldId,
|
|
622
|
+
label: field.label,
|
|
623
|
+
prompt: buildFieldStepPrompt(field, 0, 1),
|
|
624
|
+
description: field.description,
|
|
625
|
+
examples: field.examples,
|
|
626
|
+
constraints: field.constraints,
|
|
627
|
+
},
|
|
628
|
+
];
|
|
629
|
+
const nextInstruction = steps[0].prompt;
|
|
707
630
|
|
|
708
631
|
return {
|
|
709
632
|
status: 'ready',
|
|
710
633
|
stage: 'post_setup_world_requirements',
|
|
711
634
|
worldId: detail.worldId,
|
|
712
635
|
displayName: detail.displayName,
|
|
713
|
-
requiredFieldCount:
|
|
714
|
-
optionalFieldCount:
|
|
636
|
+
requiredFieldCount: 1,
|
|
637
|
+
optionalFieldCount: 0,
|
|
715
638
|
summary,
|
|
716
639
|
steps,
|
|
717
640
|
hints: detail.hints,
|
|
718
|
-
optionalContextSummary,
|
|
719
641
|
nextAction: detail.nextAction,
|
|
720
642
|
orchestration: {
|
|
721
643
|
stage: 'post_setup_world_requirements',
|
|
722
|
-
system: 'Confirm the selected world, explain
|
|
644
|
+
system: 'Confirm the selected world, explain the participant context requirement in plain language, and use join_world once that text is available.',
|
|
723
645
|
confirmation: `Confirmed world: ${detail.displayName} [${detail.worldId}].`,
|
|
724
|
-
user: [summary, nextInstruction
|
|
725
|
-
followUp:
|
|
726
|
-
? `After the user answers ${steps[0].label}, continue with the remaining required fields in order, then call join_world.`
|
|
727
|
-
: (requiredFields.length === 1
|
|
728
|
-
? 'After the user answers the required field, call join_world.'
|
|
729
|
-
: 'No required fields remain. Call join_world now.'),
|
|
646
|
+
user: [summary, nextInstruction].filter(Boolean).join('\n\n'),
|
|
647
|
+
followUp: 'After the user provides participantContextText, call join_world.',
|
|
730
648
|
},
|
|
731
649
|
};
|
|
732
650
|
}
|
|
733
651
|
|
|
734
|
-
function buildFieldLookup(worldDetail = {}) {
|
|
735
|
-
const detail = normalizeWorldDetail(worldDetail);
|
|
736
|
-
return new Map(
|
|
737
|
-
[...detail.requiredFields, ...detail.optionalFields].map((field) => [field.fieldId, field]),
|
|
738
|
-
);
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
function selectPromptFields(joinCheck = {}, worldDetail = {}, maxFieldsPerStep = 1) {
|
|
742
|
-
if (joinCheck.accepted) return [];
|
|
743
|
-
|
|
744
|
-
const fieldLookup = buildFieldLookup(worldDetail);
|
|
745
|
-
const orderedMissingFields = Array.isArray(joinCheck.missingFieldGuidance?.orderedMissingFields)
|
|
746
|
-
&& joinCheck.missingFieldGuidance.orderedMissingFields.length > 0
|
|
747
|
-
? joinCheck.missingFieldGuidance.orderedMissingFields
|
|
748
|
-
: (Array.isArray(joinCheck.missingFields) ? joinCheck.missingFields : []);
|
|
749
|
-
|
|
750
|
-
return orderedMissingFields.slice(0, Math.max(1, maxFieldsPerStep)).map((field, index) => {
|
|
751
|
-
const detailField = fieldLookup.get(field.fieldId) || {};
|
|
752
|
-
return normalizeField(
|
|
753
|
-
{
|
|
754
|
-
...detailField,
|
|
755
|
-
...field,
|
|
756
|
-
description: normalizeText(field.description, detailField.description || null),
|
|
757
|
-
examples: Array.isArray(detailField.examples) ? detailField.examples : field.examples,
|
|
758
|
-
constraints: detailField.constraints || field.constraints,
|
|
759
|
-
},
|
|
760
|
-
index,
|
|
761
|
-
{ required: true },
|
|
762
|
-
);
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function buildProfileFieldPrompt(field = {}, index = 0, total = 1) {
|
|
767
|
-
const examples = Array.isArray(field.examples) && field.examples.length > 0
|
|
768
|
-
? ` Example: ${field.examples.map((example) => quoteExample(example)).join(' or ')}.`
|
|
769
|
-
: '';
|
|
770
|
-
const description = sentenceCase(
|
|
771
|
-
field.description || `Provide ${field.label} so the world can evaluate the profile`,
|
|
772
|
-
'Provide this field so the world can evaluate the profile.',
|
|
773
|
-
);
|
|
774
|
-
const prefix = total > 1 ? `${index + 1}. ` : '';
|
|
775
|
-
|
|
776
|
-
return `${prefix}${field.label}. ${description}${examples}`;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
function listProvidedRequiredFieldIds(worldDetail = {}, profile = {}, missingFieldIds = []) {
|
|
780
|
-
const missingSet = new Set(normalizeStringList(missingFieldIds));
|
|
781
|
-
return normalizeWorldDetail(worldDetail).requiredFields
|
|
782
|
-
.filter((field) => !missingSet.has(field.fieldId) && !isEmptyProfileValue(profile[field.fieldId]))
|
|
783
|
-
.map((field) => field.fieldId);
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function buildProfileCollectionFollowUp(promptFields = []) {
|
|
787
|
-
if (promptFields.length === 0) {
|
|
788
|
-
return 'The current profile is already eligible. Continue with the next world step without restarting profile collection.';
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
const labels = promptFields.map((field) => field.label);
|
|
792
|
-
if (promptFields.length === 1) {
|
|
793
|
-
return `After the user answers ${labels[0]}, merge it into the saved profile draft and retry join_world before asking anything else.`;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
return `After the user answers ${joinAsNaturalLanguage(labels)}, merge those fields into the saved profile draft and retry join_world before asking anything else.`;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export function buildWorldProfileCollectionFlow({
|
|
800
|
-
worldDetail = {},
|
|
801
|
-
joinCheck = {},
|
|
802
|
-
profile = {},
|
|
803
|
-
maxFieldsPerStep = 1,
|
|
804
|
-
} = {}) {
|
|
805
|
-
const detail = normalizeWorldDetail(worldDetail);
|
|
806
|
-
const normalizedJoinCheck = normalizeJoinCheckResponse(joinCheck, {
|
|
807
|
-
worldId: detail.worldId,
|
|
808
|
-
profile,
|
|
809
|
-
});
|
|
810
|
-
const promptLimit = Math.max(1, normalizeInteger(maxFieldsPerStep, 1));
|
|
811
|
-
const promptFields = selectPromptFields(normalizedJoinCheck, detail, promptLimit);
|
|
812
|
-
const promptFieldIds = promptFields.map((field) => field.fieldId);
|
|
813
|
-
const providedRequiredFieldIds = listProvidedRequiredFieldIds(
|
|
814
|
-
detail,
|
|
815
|
-
normalizedJoinCheck.normalizedProfile,
|
|
816
|
-
normalizedJoinCheck.missingFieldGuidance.orderedMissingFieldIds,
|
|
817
|
-
);
|
|
818
|
-
const providedRequiredLabels = detail.requiredFields
|
|
819
|
-
.filter((field) => providedRequiredFieldIds.includes(field.fieldId))
|
|
820
|
-
.map((field) => field.label);
|
|
821
|
-
const optionalFieldLabels = detail.optionalFields.map((field) => field.label);
|
|
822
|
-
const remainingCount = normalizedJoinCheck.missingFieldGuidance.remainingRequiredFieldCount;
|
|
823
|
-
const summary = normalizedJoinCheck.accepted
|
|
824
|
-
? `All required fields for ${detail.displayName} are currently present.`
|
|
825
|
-
: `${remainingCount} required field${remainingCount === 1 ? '' : 's'} still need to be collected for ${detail.displayName}.`;
|
|
826
|
-
const savedSummary = providedRequiredLabels.length > 0
|
|
827
|
-
? `Already saved required fields: ${joinAsNaturalLanguage(providedRequiredLabels)}.`
|
|
828
|
-
: 'No required fields are saved yet.';
|
|
829
|
-
const promptSummary = promptFields.length === 0
|
|
830
|
-
? null
|
|
831
|
-
: (promptFields.length === 1
|
|
832
|
-
? 'Ask the user for this required field next:'
|
|
833
|
-
: `Ask the user for these ${promptFields.length} required fields next, and accept them in one reply if convenient:`);
|
|
834
|
-
const promptBody = promptFields.length === 0
|
|
835
|
-
? null
|
|
836
|
-
: promptFields.map((field, index) => buildProfileFieldPrompt(field, index, promptFields.length)).join('\n');
|
|
837
|
-
const optionalContextSummary = optionalFieldLabels.length > 0
|
|
838
|
-
? `Optional context the user can add or edit later: ${joinAsNaturalLanguage(optionalFieldLabels)}.`
|
|
839
|
-
: null;
|
|
840
|
-
const revalidationMode = normalizedJoinCheck.accepted
|
|
841
|
-
? 'complete'
|
|
842
|
-
: (promptFields.length > 1 ? 'after_current_batch' : 'after_each_reply');
|
|
843
|
-
|
|
844
|
-
return {
|
|
845
|
-
accepted: normalizedJoinCheck.accepted,
|
|
846
|
-
status: normalizedJoinCheck.status,
|
|
847
|
-
source: 'product_shell',
|
|
848
|
-
worldId: detail.worldId,
|
|
849
|
-
displayName: detail.displayName,
|
|
850
|
-
profile: normalizedJoinCheck.normalizedProfile,
|
|
851
|
-
promptFields,
|
|
852
|
-
promptFieldIds,
|
|
853
|
-
providedRequiredFieldIds,
|
|
854
|
-
remainingRequiredFieldCount: remainingCount,
|
|
855
|
-
nextAction: normalizedJoinCheck.nextAction,
|
|
856
|
-
revalidationCheckpoint: {
|
|
857
|
-
mode: revalidationMode,
|
|
858
|
-
promptFieldIds,
|
|
859
|
-
},
|
|
860
|
-
orchestration: {
|
|
861
|
-
stage: 'post_setup_world_profile_collection',
|
|
862
|
-
system:
|
|
863
|
-
'Use the backend join_world unmet-requirement guidance as the source of truth for the next required field prompt. After every user reply or the current batch checkpoint, merge the updates into the saved profile draft and retry join_world.',
|
|
864
|
-
confirmation: `Confirmed world: ${detail.displayName} [${detail.worldId}].`,
|
|
865
|
-
user: [summary, savedSummary, promptSummary, promptBody, optionalContextSummary].filter(Boolean).join('\n\n'),
|
|
866
|
-
followUp: buildProfileCollectionFollowUp(promptFields),
|
|
867
|
-
},
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
export function buildWorldJoinOutcomeOrchestration({ worldDetail = {}, joinResult = {} } = {}) {
|
|
872
|
-
const detail = normalizeWorldDetail(worldDetail);
|
|
873
|
-
const membershipStatus = normalizeText(
|
|
874
|
-
joinResult.membershipStatus || joinResult.membership?.status,
|
|
875
|
-
'unknown',
|
|
876
|
-
);
|
|
877
|
-
const joinSummary = joinResult.nextStageSummary?.summary
|
|
878
|
-
? sentenceCase(joinResult.nextStageSummary.summary, '')
|
|
879
|
-
: null;
|
|
880
|
-
|
|
881
|
-
return {
|
|
882
|
-
stage: 'world_join_result',
|
|
883
|
-
status: membershipStatus,
|
|
884
|
-
system:
|
|
885
|
-
'The backend already resolved the world join result. Reflect the authoritative membership outcome before any candidate-feed review, request_chat, or live-session follow-up.',
|
|
886
|
-
confirmation: `World membership in ${detail.displayName} [${detail.worldId}] is ${membershipStatus}.`,
|
|
887
|
-
user: membershipStatus === 'active'
|
|
888
|
-
? ['Joined ' + detail.displayName + ' successfully. World membership is active.', joinSummary].filter(Boolean).join(' ')
|
|
889
|
-
: `The join result for ${detail.displayName} is ${membershipStatus}.`,
|
|
890
|
-
followUp: membershipStatus === 'active'
|
|
891
|
-
? 'Use the backend-authored candidate-feed and candidate-delivery payloads for the next world step, and keep request_chat as the canonical conversation-start action.'
|
|
892
|
-
: 'Do not continue to world-member-only follow-up until membership becomes active.',
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
export function buildResolvedWorldSelectionOrchestration({
|
|
897
|
-
selection = null,
|
|
898
|
-
profileCollectionFlow = null,
|
|
899
|
-
} = {}) {
|
|
900
|
-
const selectionOrchestration = selection?.orchestration && typeof selection.orchestration === 'object' && !Array.isArray(selection.orchestration)
|
|
901
|
-
? selection.orchestration
|
|
902
|
-
: null;
|
|
903
|
-
const profileOrchestration = profileCollectionFlow?.orchestration && typeof profileCollectionFlow.orchestration === 'object' && !Array.isArray(profileCollectionFlow.orchestration)
|
|
904
|
-
? profileCollectionFlow.orchestration
|
|
905
|
-
: null;
|
|
906
|
-
|
|
907
|
-
if (!profileOrchestration) return selectionOrchestration;
|
|
908
|
-
|
|
909
|
-
return {
|
|
910
|
-
stage: normalizeText(profileOrchestration.stage, normalizeText(selectionOrchestration?.stage, null)),
|
|
911
|
-
system: normalizeText(profileOrchestration.system, normalizeText(selectionOrchestration?.system, null)),
|
|
912
|
-
confirmation: normalizeText(
|
|
913
|
-
profileOrchestration.confirmation,
|
|
914
|
-
normalizeText(selectionOrchestration?.confirmation, null),
|
|
915
|
-
),
|
|
916
|
-
user: [
|
|
917
|
-
normalizeText(profileOrchestration.confirmation, null),
|
|
918
|
-
normalizeText(profileOrchestration.user, null),
|
|
919
|
-
].filter(Boolean).join('\n\n'),
|
|
920
|
-
followUp: normalizeText(
|
|
921
|
-
profileOrchestration.followUp,
|
|
922
|
-
normalizeText(selectionOrchestration?.followUp, null),
|
|
923
|
-
),
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
|
|
927
652
|
export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail = null, limit = null } = {}) {
|
|
928
653
|
const detail = worldDetail ? normalizeWorldDetail(worldDetail) : null;
|
|
929
654
|
const normalizedFeed = normalizeCandidateFeedResponse(candidateFeed, {
|
|
@@ -53,8 +53,9 @@ export function registerFeedbackRoutes(app, { store, feedbackService }) {
|
|
|
53
53
|
details: req.body?.details,
|
|
54
54
|
reproductionSteps: req.body?.reproductionSteps,
|
|
55
55
|
worldId: req.body?.worldId,
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
conversationKey: req.body?.conversationKey,
|
|
57
|
+
turnId: req.body?.turnId,
|
|
58
|
+
deliveryId: req.body?.deliveryId,
|
|
58
59
|
targetAgentId: req.body?.targetAgentId,
|
|
59
60
|
targetAgentCode: req.body?.targetAgentCode,
|
|
60
61
|
tags: req.body?.tags,
|
|
@@ -77,7 +78,7 @@ export function registerFeedbackRoutes(app, { store, feedbackService }) {
|
|
|
77
78
|
accountId: req.query.accountId,
|
|
78
79
|
reporterAgentId: req.query.reporterAgentId,
|
|
79
80
|
worldId: req.query.worldId,
|
|
80
|
-
|
|
81
|
+
conversationKey: req.query.conversationKey,
|
|
81
82
|
source: req.query.source,
|
|
82
83
|
page: req.query.page,
|
|
83
84
|
limit: req.query.limit,
|
|
@@ -122,8 +122,9 @@ function projectFeedback(feedback = {}) {
|
|
|
122
122
|
context: feedback.context && typeof feedback.context === 'object'
|
|
123
123
|
? {
|
|
124
124
|
worldId: feedback.context.worldId || null,
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
conversationKey: feedback.context.conversationKey || null,
|
|
126
|
+
turnId: feedback.context.turnId || null,
|
|
127
|
+
deliveryId: feedback.context.deliveryId || null,
|
|
127
128
|
targetAgentId: feedback.context.targetAgentId || null,
|
|
128
129
|
targetAgentCode: feedback.context.targetAgentCode || null,
|
|
129
130
|
tags: Array.isArray(feedback.context.tags) ? feedback.context.tags : [],
|
|
@@ -133,8 +134,9 @@ function projectFeedback(feedback = {}) {
|
|
|
133
134
|
}
|
|
134
135
|
: {
|
|
135
136
|
worldId: null,
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
conversationKey: null,
|
|
138
|
+
turnId: null,
|
|
139
|
+
deliveryId: null,
|
|
138
140
|
targetAgentId: null,
|
|
139
141
|
targetAgentCode: null,
|
|
140
142
|
tags: [],
|
|
@@ -181,8 +183,9 @@ export function createFeedbackService({ store } = {}) {
|
|
|
181
183
|
},
|
|
182
184
|
context: {
|
|
183
185
|
worldId: normalizeText(input.worldId, normalizeText(context.worldId, null)),
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
conversationKey: normalizeText(input.conversationKey, normalizeText(context.conversationKey, null)),
|
|
187
|
+
turnId: normalizeText(input.turnId, normalizeText(context.turnId, null)),
|
|
188
|
+
deliveryId: normalizeText(input.deliveryId, normalizeText(context.deliveryId, null)),
|
|
186
189
|
targetAgentId: normalizeText(input.targetAgentId, normalizeText(context.targetAgentId, null)),
|
|
187
190
|
targetAgentCode: normalizeText(input.targetAgentCode, normalizeText(context.targetAgentCode, null)),
|
|
188
191
|
tags: normalizeStringList(input.tags || context.tags),
|
|
@@ -223,7 +226,7 @@ export function createFeedbackService({ store } = {}) {
|
|
|
223
226
|
accountId: normalizeText(filters.accountId, null),
|
|
224
227
|
reporterAgentId: normalizeText(filters.reporterAgentId, null),
|
|
225
228
|
worldId: normalizeText(filters.worldId, null),
|
|
226
|
-
|
|
229
|
+
conversationKey: normalizeText(filters.conversationKey, null),
|
|
227
230
|
source: normalizeText(filters.source, null),
|
|
228
231
|
page,
|
|
229
232
|
limit,
|
|
@@ -245,7 +248,7 @@ export function createFeedbackService({ store } = {}) {
|
|
|
245
248
|
accountId: normalizeText(filters.accountId, null),
|
|
246
249
|
reporterAgentId: normalizeText(filters.reporterAgentId, null),
|
|
247
250
|
worldId: normalizeText(filters.worldId, null),
|
|
248
|
-
|
|
251
|
+
conversationKey: normalizeText(filters.conversationKey, null),
|
|
249
252
|
source: normalizeText(filters.source, null),
|
|
250
253
|
},
|
|
251
254
|
};
|
|
@@ -10,7 +10,7 @@ import { createMembershipService } from './membership/membership-service.js';
|
|
|
10
10
|
import { createMatchmakingService } from './matching/matchmaking-service.js';
|
|
11
11
|
import { createWorldSearchService } from './search/search-service.js';
|
|
12
12
|
import { createResultService } from './results/result-service.js';
|
|
13
|
-
import {
|
|
13
|
+
import { createWorldConversationOrchestrator } from './orchestration/world-conversation-orchestrator.js';
|
|
14
14
|
import { createSocialService } from './social/social-service.js';
|
|
15
15
|
import { registerSocialRoutes } from './social/social-routes.js';
|
|
16
16
|
import { createFriendService } from './social/friend-service.js';
|
|
@@ -60,7 +60,7 @@ export function createClaworldProductShell({
|
|
|
60
60
|
return socialLookupService.lookupAgentByCode(input);
|
|
61
61
|
},
|
|
62
62
|
};
|
|
63
|
-
const
|
|
63
|
+
const worldConversationOrchestrator = createWorldConversationOrchestrator({
|
|
64
64
|
worldService,
|
|
65
65
|
resultService,
|
|
66
66
|
});
|
|
@@ -79,7 +79,7 @@ export function createClaworldProductShell({
|
|
|
79
79
|
moderation: worldAdminService,
|
|
80
80
|
feedback: feedbackService,
|
|
81
81
|
results: resultService,
|
|
82
|
-
orchestration:
|
|
82
|
+
orchestration: worldConversationOrchestrator,
|
|
83
83
|
},
|
|
84
84
|
registerRoutes(app) {
|
|
85
85
|
registerOnboardingRoutes(app, { onboardingService, store });
|
|
@@ -94,7 +94,7 @@ export function createClaworldProductShell({
|
|
|
94
94
|
searchService,
|
|
95
95
|
worldBroadcastService,
|
|
96
96
|
worldAdminService,
|
|
97
|
-
|
|
97
|
+
worldConversationOrchestrator,
|
|
98
98
|
});
|
|
99
99
|
registerSocialRoutes(app, { socialService: socialLookupService });
|
|
100
100
|
registerFeedbackRoutes(app, { store, feedbackService });
|
|
@@ -138,11 +138,10 @@ export function createClaworldProductShell({
|
|
|
138
138
|
'POST /v1/worlds/:worldId/search',
|
|
139
139
|
'POST /v1/worlds/:worldId/broadcast',
|
|
140
140
|
'GET /v1/worlds/:worldId/candidates',
|
|
141
|
-
'POST /v1/worlds/:worldId/join-check',
|
|
142
141
|
'POST /v1/worlds/:worldId/join',
|
|
143
142
|
'GET /v1/worlds/:worldId/memberships',
|
|
144
143
|
'POST /v1/worlds/:worldId/memberships',
|
|
145
|
-
'POST /v1/worlds/:worldId/
|
|
144
|
+
'POST /v1/worlds/:worldId/conversation-preview',
|
|
146
145
|
'GET /v1/social/agents/lookup',
|
|
147
146
|
'POST /v1/feedback',
|
|
148
147
|
'GET /v1/moderation/worlds',
|