@xfxstudio/claworld 2026.4.28-testing → 2026.4.28-testing.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,12 +10,6 @@ function normalizeInteger(value, fallback = 0) {
10
10
  return Math.max(0, Math.trunc(parsed));
11
11
  }
12
12
 
13
- function normalizeNumber(value, fallback = null) {
14
- const parsed = Number(value);
15
- if (!Number.isFinite(parsed)) return fallback;
16
- return parsed;
17
- }
18
-
19
13
  function normalizeStringList(values = []) {
20
14
  if (!Array.isArray(values)) return [];
21
15
  return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
@@ -214,147 +208,6 @@ function normalizeWorldDetail(payload = {}) {
214
208
  };
215
209
  }
216
210
 
217
- function normalizeProfileSummaryField(field = {}, index = 0) {
218
- const fieldId = normalizeText(field.fieldId || field.id, `field_${index + 1}`);
219
- const value = Array.isArray(field.value)
220
- ? normalizeStringList(field.value)
221
- : normalizeText(field.value, null);
222
-
223
- if (value == null || (Array.isArray(value) && value.length === 0)) {
224
- return null;
225
- }
226
-
227
- return {
228
- fieldId,
229
- label: normalizeText(field.label, fieldId),
230
- value,
231
- };
232
- }
233
-
234
- function normalizeCandidateProfileSummary(summary = {}) {
235
- return {
236
- displayName: normalizeText(summary.displayName, null),
237
- headline: normalizeText(summary.headline, null),
238
- requiredFields: Array.isArray(summary.requiredFields)
239
- ? summary.requiredFields.map((field, index) => normalizeProfileSummaryField(field, index)).filter(Boolean)
240
- : [],
241
- optionalFields: Array.isArray(summary.optionalFields)
242
- ? summary.optionalFields.map((field, index) => normalizeProfileSummaryField(field, index)).filter(Boolean)
243
- : [],
244
- };
245
- }
246
-
247
- function normalizeCompatibilitySignal(signal = {}, index = 0) {
248
- return {
249
- signalId: normalizeText(signal.signalId, `signal_${index + 1}`),
250
- type: normalizeText(signal.type, 'world_ready'),
251
- fieldIds: normalizeStringList(signal.fieldIds),
252
- score: normalizeNumber(signal.score, 0),
253
- summary: normalizeText(signal.summary, ''),
254
- };
255
- }
256
-
257
- function normalizeDeliveryReason(reason = {}) {
258
- return {
259
- code: normalizeText(reason.code, null),
260
- matchedFieldIds: normalizeStringList(reason.matchedFieldIds),
261
- summary: normalizeText(reason.summary, ''),
262
- };
263
- }
264
-
265
- function normalizeWorldRole(worldRole, fallback = null) {
266
- const normalized = normalizeText(worldRole, fallback);
267
- return ['owner', 'member'].includes(normalized) ? normalized : fallback;
268
- }
269
-
270
- function normalizeCandidate(candidate = {}, index = 0) {
271
- const normalizedRank = normalizeNumber(candidate.rank, null);
272
- const displayName = normalizeText(
273
- candidate.displayName || candidate.profileSummary?.displayName || candidate.requestChat?.displayName,
274
- null,
275
- );
276
- const agentCode = normalizeText(
277
- candidate.agentCode || candidate.requestChat?.agentCode,
278
- null,
279
- )?.toUpperCase() || null;
280
- const requestChat = displayName && agentCode
281
- ? {
282
- worldId: normalizeText(candidate.requestChat?.worldId, normalizeText(candidate.worldId, 'unknown-world')),
283
- displayName,
284
- agentCode,
285
- }
286
- : null;
287
-
288
- return {
289
- candidateId: normalizeText(candidate.candidateId, `candidate_${index + 1}`),
290
- worldId: normalizeText(candidate.worldId, 'unknown-world'),
291
- worldRole: normalizeWorldRole(candidate.worldRole, null),
292
- sourceMembershipId: normalizeText(candidate.sourceMembershipId, null),
293
- online: candidate.online === true,
294
- displayName,
295
- agentCode,
296
- requestChat,
297
- profileSummary: normalizeCandidateProfileSummary(candidate.profileSummary),
298
- compatibilitySignals: Array.isArray(candidate.compatibilitySignals)
299
- ? candidate.compatibilitySignals.map((signal, signalIndex) => normalizeCompatibilitySignal(signal, signalIndex))
300
- : [],
301
- deliveryReason: normalizeDeliveryReason(candidate.deliveryReason),
302
- expiresAt: normalizeText(candidate.expiresAt, null),
303
- joinedAt: normalizeText(candidate.joinedAt, null),
304
- rank: normalizedRank == null ? null : Math.max(1, Math.trunc(normalizedRank)),
305
- score: normalizeNumber(candidate.score, null),
306
- };
307
- }
308
-
309
- function normalizeCandidateFeedResponse(payload = {}, { worldId = null } = {}) {
310
- const candidates = Array.isArray(payload.candidates)
311
- ? payload.candidates.map((candidate, index) => normalizeCandidate(candidate, index))
312
- : [];
313
-
314
- return {
315
- worldId: normalizeText(payload.worldId, worldId || 'unknown-world'),
316
- viewerMembershipId: normalizeText(payload.viewerMembershipId, null),
317
- generatedAt: normalizeText(payload.generatedAt, null),
318
- expiresAt: normalizeText(payload.expiresAt, null),
319
- deliveryMode: normalizeText(payload.deliveryMode, 'agent_review_before_live_session'),
320
- nextAction: normalizeText(
321
- payload.nextAction,
322
- candidates.length > 0 ? 'review_candidates_then_request_chat' : 'wait_for_more_candidates',
323
- ),
324
- candidateSource: normalizeText(payload.candidateSource, 'active_memberships_online'),
325
- candidateModel: payload.candidateModel && typeof payload.candidateModel === 'object' ? payload.candidateModel : {},
326
- strategy: payload.strategy && typeof payload.strategy === 'object' ? payload.strategy : {},
327
- limit: normalizeInteger(payload.limit, candidates.length),
328
- totalCandidates: normalizeInteger(payload.totalCandidates, candidates.length),
329
- status: normalizeText(payload.status, candidates.length > 0 ? 'feed_ready' : 'no_candidates_ready'),
330
- candidates,
331
- };
332
- }
333
-
334
- function summarizeProfileValue(value) {
335
- if (Array.isArray(value)) return joinAsNaturalLanguage(value.map((entry) => String(entry).trim()).filter(Boolean));
336
- return normalizeText(value, '');
337
- }
338
-
339
- function summarizeProfileFields(fields = []) {
340
- return fields
341
- .map((field) => {
342
- const value = summarizeProfileValue(field.value);
343
- if (!value) return null;
344
- return `${field.label}: ${value}`;
345
- })
346
- .filter(Boolean);
347
- }
348
-
349
- function buildCandidateDeliverySummaryLine(candidateSummary = {}, index = 0) {
350
- const likesReceived = Number(candidateSummary.worldFeedbackSummary?.likesReceived || 0);
351
- const dislikesReceived = Number(candidateSummary.worldFeedbackSummary?.dislikesReceived || 0);
352
- const feedbackLine = likesReceived > 0 || dislikesReceived > 0
353
- ? ` World feedback in this world: ${likesReceived} like${likesReceived === 1 ? '' : 's'}, ${dislikesReceived} dislike${dislikesReceived === 1 ? '' : 's'}.`
354
- : '';
355
- return `${index + 1}. ${candidateSummary.summary}${feedbackLine}`;
356
- }
357
-
358
211
  function formatConversationOverview(detail = {}) {
359
212
  const conversationOverview = detail.conversationOverview && typeof detail.conversationOverview === 'object'
360
213
  ? detail.conversationOverview
@@ -605,133 +458,11 @@ export function buildRequiredFieldExplanation(worldDetail = {}) {
605
458
  };
606
459
  }
607
460
 
608
- export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail = null, limit = null } = {}) {
609
- const detail = worldDetail ? normalizeWorldDetail(worldDetail) : null;
610
- const normalizedFeed = normalizeCandidateFeedResponse(candidateFeed, {
611
- worldId: detail?.worldId || candidateFeed.worldId || null,
612
- });
613
- const summaryLimit = Math.max(
614
- 1,
615
- normalizeInteger(limit, normalizedFeed.candidates.length || normalizedFeed.totalCandidates || 1),
616
- );
617
- const displayName = detail?.displayName || normalizedFeed.worldId || 'the selected world';
618
- const requestChatAction = {
619
- action: 'request_chat',
620
- worldId: normalizedFeed.worldId,
621
- requiredFields: ['worldId', 'displayName', 'agentCode', 'openingMessage'],
622
- summary:
623
- 'After the user chooses a candidate, request_chat with this worldId, displayName, agentCode, and a non-blank openingMessage.',
624
- };
625
- const candidateSummaries = normalizedFeed.candidates.slice(0, summaryLimit).map((candidate, index) => {
626
- const name = candidate.profileSummary.displayName || `Candidate ${index + 1}`;
627
- const requiredFieldSummary = summarizeProfileFields(candidate.profileSummary.requiredFields);
628
- const optionalFieldSummary = summarizeProfileFields(candidate.profileSummary.optionalFields);
629
- const compatibilitySummary = candidate.compatibilitySignals
630
- .map((signal) => sentenceCase(signal.summary, ''))
631
- .filter(Boolean);
632
- const deliveryReasonSummary = sentenceCase(candidate.deliveryReason.summary, '');
633
- const availabilitySummary = candidate.online === true ? 'Online now.' : 'Currently offline.';
634
- const roleSummary = candidate.worldRole ? `World role: ${candidate.worldRole}.` : null;
635
- const scoreSummary = candidate.score == null
636
- ? null
637
- : `Score ${candidate.score}${candidate.rank == null ? '' : `, rank ${candidate.rank}`}.`;
638
- const summary = [
639
- candidate.profileSummary.headline ? `${name}: ${candidate.profileSummary.headline}.` : `${name}.`,
640
- requiredFieldSummary.length > 0 ? `Required profile fields: ${requiredFieldSummary.join('; ')}.` : null,
641
- optionalFieldSummary.length > 0 ? `Optional context: ${optionalFieldSummary.join('; ')}.` : null,
642
- compatibilitySummary.length > 0 ? compatibilitySummary.join(' ') : null,
643
- deliveryReasonSummary || null,
644
- roleSummary,
645
- availabilitySummary,
646
- scoreSummary,
647
- ].filter(Boolean).join(' ');
648
-
649
- return {
650
- candidateId: candidate.candidateId,
651
- sourceMembershipId: candidate.sourceMembershipId,
652
- online: candidate.online === true,
653
- worldRole: candidate.worldRole,
654
- agentCode: candidate.agentCode,
655
- requestChat: candidate.requestChat,
656
- displayName: name,
657
- headline: candidate.profileSummary.headline,
658
- rank: candidate.rank,
659
- score: candidate.score,
660
- requiredFieldSummary,
661
- optionalFieldSummary,
662
- compatibilitySummary,
663
- deliveryReasonSummary: deliveryReasonSummary || null,
664
- worldFeedbackSummary: candidate.worldFeedbackSummary || {
665
- likesReceived: 0,
666
- dislikesReceived: 0,
667
- },
668
- expiresAt: candidate.expiresAt,
669
- summary,
670
- };
671
- });
672
- const deliveredCandidateCount = candidateSummaries.length;
673
- const totalCandidateCount = Math.max(normalizedFeed.totalCandidates, deliveredCandidateCount);
674
- const remainingCandidateCount = Math.max(totalCandidateCount - deliveredCandidateCount, 0);
675
- const heading = deliveredCandidateCount > 0
676
- ? `${displayName} has ${deliveredCandidateCount} online candidate profile ${deliveredCandidateCount === 1 ? 'summary' : 'summaries'} ready for review now.`
677
- : `No online candidate profile summaries are ready for review in ${displayName} yet.`;
678
- const promptBody = deliveredCandidateCount > 0
679
- ? candidateSummaries.map((summary, index) => buildCandidateDeliverySummaryLine(summary, index)).join('\n\n')
680
- : 'No online candidates are currently available from the active-membership feed.';
681
-
682
- return {
683
- worldId: normalizedFeed.worldId,
684
- status: deliveredCandidateCount > 0 ? 'candidate_summary_ready' : 'candidate_summary_pending',
685
- deliveredCandidateCount,
686
- totalCandidateCount,
687
- remainingCandidateCount,
688
- requestChatAction,
689
- candidateSummaries,
690
- nextAction: deliveredCandidateCount > 0
691
- ? normalizedFeed.nextAction
692
- : 'wait_for_more_candidates',
693
- orchestration: {
694
- stage: 'post_join_candidate_delivery',
695
- system:
696
- 'Use the backend-authored candidate summaries already attached to this payload. Candidate requestChat payloads are the canonical follow-up inputs for world-scoped contact establishment.',
697
- confirmation: `Candidate review payload for ${displayName} [${normalizedFeed.worldId}].`,
698
- user: [heading, promptBody].filter(Boolean).join('\n\n'),
699
- followUp: deliveredCandidateCount > 0
700
- ? (remainingCandidateCount > 0
701
- ? `Share these ${deliveredCandidateCount} candidate summaries first. If the user chooses someone now, continue with request_chat using that candidate's {worldId, displayName, agentCode} plus a non-blank openingMessage from the user. If they want more options first, continue with the remaining ${remainingCandidateCount} candidate${remainingCandidateCount === 1 ? '' : 's'} from the same feed.`
702
- : 'Share these candidate summaries and, if the user chooses one, continue with request_chat using the attached {worldId, displayName, agentCode} payload plus a non-blank openingMessage from the user.')
703
- : 'Tell the user candidate delivery can be retried later through the same backend-authored world flow.',
704
- },
705
- };
706
- }
707
-
708
461
  export function buildResolvedWorldJoinOrchestration({
709
462
  joinResult = null,
710
- candidateDelivery = null,
711
463
  } = {}) {
712
464
  const joinOrchestration = joinResult?.orchestration && typeof joinResult.orchestration === 'object' && !Array.isArray(joinResult.orchestration)
713
465
  ? joinResult.orchestration
714
466
  : null;
715
- const candidateOrchestration = candidateDelivery?.orchestration && typeof candidateDelivery.orchestration === 'object' && !Array.isArray(candidateDelivery.orchestration)
716
- ? candidateDelivery.orchestration
717
- : null;
718
-
719
- if (!candidateOrchestration) return joinOrchestration;
720
-
721
- return {
722
- stage: normalizeText(candidateOrchestration.stage, normalizeText(joinOrchestration?.stage, null)),
723
- system: normalizeText(candidateOrchestration.system, normalizeText(joinOrchestration?.system, null)),
724
- confirmation: normalizeText(
725
- joinOrchestration?.confirmation,
726
- normalizeText(candidateOrchestration.confirmation, null),
727
- ),
728
- user: [
729
- normalizeText(joinOrchestration?.user, normalizeText(joinOrchestration?.confirmation, null)),
730
- normalizeText(candidateOrchestration.user, null),
731
- ].filter(Boolean).join('\n\n'),
732
- followUp: normalizeText(
733
- candidateOrchestration.followUp,
734
- normalizeText(joinOrchestration?.followUp, null),
735
- ),
736
- };
467
+ return joinOrchestration;
737
468
  }