@xfxstudio/claworld 0.1.3 → 0.1.5
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/index.js +2 -2
- package/openclaw.plugin.json +6 -3
- package/package.json +3 -2
- package/skills/claworld-help/SKILL.md +302 -0
- package/skills/claworld-join-and-chat/SKILL.md +386 -0
- package/skills/claworld-manage-worlds/SKILL.md +337 -0
- package/src/openclaw/installer/cli.js +0 -11
- package/src/openclaw/installer/core.js +1 -8
- package/src/openclaw/plugin/claworld-channel-plugin.js +43 -4
- package/src/openclaw/plugin/config-schema.js +1 -1
- package/src/openclaw/plugin/managed-config.js +42 -31
- package/src/openclaw/plugin/register.js +805 -542
- package/src/openclaw/plugin/relay-client.js +1 -1
- package/src/openclaw/runtime/product-shell-helper.js +2 -1
- package/src/openclaw/runtime/tool-contracts.js +12 -1
- package/src/openclaw/runtime/tool-inventory.js +28 -24
- package/src/product-shell/catalog/default-world-catalog.js +6 -6
- package/src/product-shell/contracts/candidate-feed.js +14 -4
- package/src/product-shell/contracts/world-manifest.js +19 -1
- package/src/product-shell/contracts/world-orchestration.js +8 -4
- package/src/product-shell/index.js +1 -1
- package/src/product-shell/matching/matchmaking-service.js +39 -5
- package/src/product-shell/social/chat-request-service.js +8 -1
- package/src/product-shell/worlds/world-admin-service.js +2 -2
|
@@ -422,6 +422,7 @@ function normalizeCandidate(candidate = {}, index = 0) {
|
|
|
422
422
|
worldId: normalizeText(candidate.worldId, 'unknown-world'),
|
|
423
423
|
targetAgentId: normalizeText(candidate.targetAgentId, null),
|
|
424
424
|
sourceMembershipId: normalizeText(candidate.sourceMembershipId, null),
|
|
425
|
+
online: candidate.online === true,
|
|
425
426
|
targetAgentId,
|
|
426
427
|
requestChat,
|
|
427
428
|
profileSummary: normalizeCandidateProfileSummary(candidate.profileSummary),
|
|
@@ -457,7 +458,7 @@ function normalizeCandidateFeedResponse(payload = {}, { worldId = null, agentId
|
|
|
457
458
|
candidateDelivery: payload.candidateDelivery && typeof payload.candidateDelivery === 'object'
|
|
458
459
|
? payload.candidateDelivery
|
|
459
460
|
: null,
|
|
460
|
-
candidateSource: normalizeText(payload.candidateSource, '
|
|
461
|
+
candidateSource: normalizeText(payload.candidateSource, 'active_memberships_online'),
|
|
461
462
|
candidateModel: payload.candidateModel && typeof payload.candidateModel === 'object' ? payload.candidateModel : {},
|
|
462
463
|
strategy: payload.strategy && typeof payload.strategy === 'object' ? payload.strategy : {},
|
|
463
464
|
limit: normalizeInteger(payload.limit, candidates.length),
|
|
@@ -230,6 +230,7 @@ function projectToolCandidateDeliverySummary(
|
|
|
230
230
|
sourceMembershipId: normalizeText(summary.sourceMembershipId, null),
|
|
231
231
|
displayName: normalizeText(summary.displayName, null),
|
|
232
232
|
headline: normalizeText(summary.headline, null),
|
|
233
|
+
online: summary.online === true,
|
|
233
234
|
rank: normalizeOptionalInteger(summary.rank, null),
|
|
234
235
|
score: normalizeOptionalInteger(summary.score, null),
|
|
235
236
|
targetAgentId: normalizeText(summary.targetAgentId, summary.requestChat?.targetAgentId || null),
|
|
@@ -383,6 +384,7 @@ function projectToolCandidateSummary(summary = {}, index = 0) {
|
|
|
383
384
|
targetAgentId: normalizeText(summary.targetAgentId, null),
|
|
384
385
|
displayName: normalizeText(summary.displayName, `Candidate ${index + 1}`),
|
|
385
386
|
headline: normalizeText(summary.headline, null),
|
|
387
|
+
online: summary.online === true,
|
|
386
388
|
rank: normalizeInteger(summary.rank, 0) || null,
|
|
387
389
|
score: normalizeInteger(summary.score, 0) || null,
|
|
388
390
|
summary: normalizeText(summary.summary, null),
|
|
@@ -405,6 +407,7 @@ function projectToolCandidateFeed(joinResult = {}) {
|
|
|
405
407
|
targetAgentId: candidate.targetAgentId,
|
|
406
408
|
displayName: candidate.profileSummary?.displayName,
|
|
407
409
|
headline: candidate.profileSummary?.headline,
|
|
410
|
+
online: candidate.online === true,
|
|
408
411
|
rank: candidate.rank,
|
|
409
412
|
score: candidate.score,
|
|
410
413
|
summary: normalizeText(candidate.deliveryReason?.summary, null),
|
|
@@ -783,6 +786,12 @@ function projectChatRequestKickoff(kickoff = {}) {
|
|
|
783
786
|
return {
|
|
784
787
|
status: normalizeText(kickoff.status, 'skipped'),
|
|
785
788
|
deliveredAt: normalizeText(kickoff.deliveredAt, null),
|
|
789
|
+
relaySessionPreparedAt: normalizeText(kickoff.relaySessionPreparedAt, null),
|
|
790
|
+
acceptedRoundPreparedAt: normalizeText(kickoff.acceptedRoundPreparedAt, null),
|
|
791
|
+
senderKickoffDeliveredAt: normalizeText(kickoff.senderKickoffDeliveredAt, normalizeText(kickoff.deliveredAt, null)),
|
|
792
|
+
openerAcceptedAt: normalizeText(kickoff.openerAcceptedAt, null),
|
|
793
|
+
openerDeliveredAt: normalizeText(kickoff.openerDeliveredAt, null),
|
|
794
|
+
liveChatEstablishedAt: normalizeText(kickoff.liveChatEstablishedAt, null),
|
|
786
795
|
reason: normalizeText(kickoff.reason, null),
|
|
787
796
|
};
|
|
788
797
|
}
|
|
@@ -883,8 +892,10 @@ export function projectToolChatRequestMutationResponse(result = {}, { accountId
|
|
|
883
892
|
nextAction: normalizeText(
|
|
884
893
|
result.nextAction,
|
|
885
894
|
normalizedStatus === 'accepted'
|
|
886
|
-
? kickoff?.status === '
|
|
895
|
+
? kickoff?.status === 'established'
|
|
887
896
|
? 'runtime_owns_live_conversation'
|
|
897
|
+
: kickoff?.status === 'sent'
|
|
898
|
+
? 'wait_for_sender_opener_delivery'
|
|
888
899
|
: kickoff?.status === 'failed'
|
|
889
900
|
? 'backend_kickoff_failed'
|
|
890
901
|
: 'chat_request_accepted_without_opening_message'
|
|
@@ -1,27 +1,16 @@
|
|
|
1
1
|
export const CLAWORLD_TOOL_CONTRACT_VERSION = 'v1';
|
|
2
2
|
|
|
3
|
-
export const CLAWORLD_FRIEND_REQUEST_TOOL_NAMES = Object.freeze([
|
|
4
|
-
'claworld_send_friend_request',
|
|
5
|
-
'claworld_list_friend_requests',
|
|
6
|
-
'claworld_accept_friend_request',
|
|
7
|
-
'claworld_reject_friend_request',
|
|
8
|
-
]);
|
|
9
|
-
|
|
10
3
|
export const CLAWORLD_CHAT_REQUEST_TOOL_NAMES = Object.freeze([
|
|
11
4
|
'claworld_request_chat',
|
|
12
5
|
'claworld_list_chat_requests',
|
|
13
6
|
'claworld_accept_chat_request',
|
|
14
7
|
]);
|
|
15
8
|
|
|
16
|
-
export const
|
|
17
|
-
|
|
18
|
-
...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
|
|
9
|
+
export const CLAWORLD_BOOTSTRAP_TOOL_NAMES = Object.freeze([
|
|
10
|
+
'claworld_pair_agent',
|
|
19
11
|
]);
|
|
20
12
|
|
|
21
|
-
export const
|
|
22
|
-
...CLAWORLD_REQUEST_TOOL_NAMES,
|
|
23
|
-
'claworld_pair_agent',
|
|
24
|
-
'claworld_resolve_agent',
|
|
13
|
+
export const CLAWORLD_FEEDBACK_TOOL_NAMES = Object.freeze([
|
|
25
14
|
'claworld_submit_feedback',
|
|
26
15
|
]);
|
|
27
16
|
|
|
@@ -29,27 +18,38 @@ export const CLAWORLD_WORLD_TOOL_NAMES = Object.freeze([
|
|
|
29
18
|
'claworld_list_worlds',
|
|
30
19
|
'claworld_get_world_detail',
|
|
31
20
|
'claworld_join_world',
|
|
32
|
-
'claworld_broadcast_world',
|
|
33
21
|
]);
|
|
34
22
|
|
|
35
|
-
export const
|
|
23
|
+
export const CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES = Object.freeze([
|
|
24
|
+
'claworld_create_world',
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export const CLAWORLD_COMPATIBILITY_TOOL_NAMES = Object.freeze([
|
|
36
28
|
'claworld_prepare_world_join',
|
|
37
29
|
'claworld_search_world',
|
|
38
30
|
]);
|
|
39
31
|
|
|
40
|
-
export const
|
|
41
|
-
'
|
|
32
|
+
export const CLAWORLD_RETIRED_PUBLIC_TOOL_NAMES = Object.freeze([
|
|
33
|
+
'claworld_send_friend_request',
|
|
34
|
+
'claworld_list_friend_requests',
|
|
35
|
+
'claworld_accept_friend_request',
|
|
36
|
+
'claworld_reject_friend_request',
|
|
37
|
+
'claworld_broadcast_world',
|
|
42
38
|
'claworld_list_owned_worlds',
|
|
43
39
|
'claworld_manage_world',
|
|
40
|
+
'claworld_resolve_agent',
|
|
44
41
|
]);
|
|
45
42
|
|
|
46
|
-
export const
|
|
43
|
+
export const CLAWORLD_REGISTERED_TOOL_NAMES = Object.freeze([
|
|
44
|
+
...CLAWORLD_BOOTSTRAP_TOOL_NAMES,
|
|
47
45
|
...CLAWORLD_WORLD_TOOL_NAMES,
|
|
48
|
-
...
|
|
49
|
-
|
|
50
|
-
...
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
...CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES,
|
|
47
|
+
...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
|
|
48
|
+
...CLAWORLD_FEEDBACK_TOOL_NAMES,
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
export const CLAWORLD_PUBLIC_TOOL_NAMES = Object.freeze([
|
|
52
|
+
...CLAWORLD_REGISTERED_TOOL_NAMES,
|
|
53
53
|
]);
|
|
54
54
|
|
|
55
55
|
export const CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES = Object.freeze([
|
|
@@ -65,7 +65,11 @@ export const CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES = Object.freeze([
|
|
|
65
65
|
]);
|
|
66
66
|
|
|
67
67
|
export const CLAWORLD_PLUGIN_SMOKE_REQUIRED_TOOL_NAMES = Object.freeze([
|
|
68
|
+
...CLAWORLD_BOOTSTRAP_TOOL_NAMES,
|
|
68
69
|
...CLAWORLD_WORLD_TOOL_NAMES,
|
|
70
|
+
...CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES,
|
|
71
|
+
...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
|
|
72
|
+
...CLAWORLD_FEEDBACK_TOOL_NAMES,
|
|
69
73
|
]);
|
|
70
74
|
|
|
71
75
|
export const CLAWORLD_TOOL_PROFILES = Object.freeze({
|
|
@@ -83,8 +83,8 @@ export const DEFAULT_WORLD_MANIFESTS = Object.freeze([
|
|
|
83
83
|
mode: 'scored_push',
|
|
84
84
|
cadence: 'periodic',
|
|
85
85
|
strategySummary:
|
|
86
|
-
'Score active memberships by intent, location, and interests, deliver candidate summaries first, and route live contact through request_chat after review.',
|
|
87
|
-
candidateSources: ['
|
|
86
|
+
'Score active online memberships by intent, location, and interests, deliver candidate summaries first, and route live contact through request_chat after review.',
|
|
87
|
+
candidateSources: ['active_memberships_online'],
|
|
88
88
|
},
|
|
89
89
|
sessionTemplate: {
|
|
90
90
|
mode: 'a2a',
|
|
@@ -179,8 +179,8 @@ export const DEFAULT_WORLD_MANIFESTS = Object.freeze([
|
|
|
179
179
|
mode: 'intent_filter',
|
|
180
180
|
cadence: 'on_demand',
|
|
181
181
|
strategySummary:
|
|
182
|
-
'Filter by capability overlap, deliver candidate summaries first, and let members request_chat before negotiating fit in a short session.',
|
|
183
|
-
candidateSources: ['
|
|
182
|
+
'Filter active online world members by capability overlap, deliver candidate summaries first, and let members request_chat before negotiating fit in a short session.',
|
|
183
|
+
candidateSources: ['active_memberships_online'],
|
|
184
184
|
},
|
|
185
185
|
sessionTemplate: {
|
|
186
186
|
mode: 'a2a',
|
|
@@ -273,8 +273,8 @@ export const DEFAULT_WORLD_MANIFESTS = Object.freeze([
|
|
|
273
273
|
mode: 'profile_overlap',
|
|
274
274
|
cadence: 'periodic',
|
|
275
275
|
strategySummary:
|
|
276
|
-
'Use target role, experience summary, and location/work mode as the first-pass scoring surface, deliver candidate summaries, and route contact through request_chat after review.',
|
|
277
|
-
candidateSources: ['
|
|
276
|
+
'Use active online memberships plus target role, experience summary, and location/work mode as the first-pass scoring surface, deliver candidate summaries, and route contact through request_chat after review.',
|
|
277
|
+
candidateSources: ['active_memberships_online'],
|
|
278
278
|
},
|
|
279
279
|
sessionTemplate: {
|
|
280
280
|
mode: 'a2a',
|
|
@@ -7,6 +7,7 @@ export const CANDIDATE_OBJECT_FIELDS = Object.freeze([
|
|
|
7
7
|
'worldId',
|
|
8
8
|
'targetAgentId',
|
|
9
9
|
'sourceMembershipId',
|
|
10
|
+
'online',
|
|
10
11
|
'requestChat',
|
|
11
12
|
'profileSummary',
|
|
12
13
|
'compatibilitySignals',
|
|
@@ -180,7 +181,7 @@ function buildCompatibilitySignals(world, viewerProfile = {}, candidateProfile =
|
|
|
180
181
|
type: 'world_ready',
|
|
181
182
|
fieldIds: [],
|
|
182
183
|
score: 0.05,
|
|
183
|
-
summary: 'Candidate
|
|
184
|
+
summary: 'Candidate is online with an active world membership and is ready for agent review before live session handoff.',
|
|
184
185
|
}),
|
|
185
186
|
];
|
|
186
187
|
}
|
|
@@ -192,7 +193,7 @@ function buildDeliveryReason(signals = []) {
|
|
|
192
193
|
return {
|
|
193
194
|
code: 'world_membership_ready',
|
|
194
195
|
matchedFieldIds: [],
|
|
195
|
-
summary: 'Delivered for manual review because the candidate is active in this world, even though no direct profile overlap signal was detected yet.',
|
|
196
|
+
summary: 'Delivered for manual review because the candidate is online and active in this world, even though no direct profile overlap signal was detected yet.',
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
199
|
|
|
@@ -264,7 +265,7 @@ export function projectCandidateFeedModel(world) {
|
|
|
264
265
|
},
|
|
265
266
|
liveDeliveryEvent: projectLiveDeliveryEvent(world, candidateFields),
|
|
266
267
|
summary:
|
|
267
|
-
'Active members can review candidate opportunities first, then call request_chat with the selected targetAgentId when they want to start a world-scoped conversation request.',
|
|
268
|
+
'Active online members can review candidate opportunities first, then call request_chat with the selected targetAgentId when they want to start a world-scoped conversation request.',
|
|
268
269
|
status: 'phase1_candidate_feed',
|
|
269
270
|
};
|
|
270
271
|
}
|
|
@@ -274,6 +275,7 @@ function projectCandidateOpportunity({
|
|
|
274
275
|
viewerProfile,
|
|
275
276
|
candidateMembership,
|
|
276
277
|
candidateAgent,
|
|
278
|
+
candidatePresence,
|
|
277
279
|
expiresAt,
|
|
278
280
|
}) {
|
|
279
281
|
const profileSnapshot = candidateMembership.profileSnapshot || {};
|
|
@@ -290,6 +292,7 @@ function projectCandidateOpportunity({
|
|
|
290
292
|
worldId: world.worldId,
|
|
291
293
|
sourceMembershipId: candidateMembership.membershipId,
|
|
292
294
|
targetAgentId: requestChat?.targetAgentId || null,
|
|
295
|
+
online: candidatePresence?.online === true,
|
|
293
296
|
requestChat,
|
|
294
297
|
profileSummary: projectProfileSummary(world, profileSnapshot, candidateAgent),
|
|
295
298
|
compatibilitySignals,
|
|
@@ -304,6 +307,7 @@ export function buildCandidateFeed({
|
|
|
304
307
|
viewerAgent = null,
|
|
305
308
|
candidateMemberships = [],
|
|
306
309
|
getAgent = () => null,
|
|
310
|
+
getPresence = () => ({ online: true }),
|
|
307
311
|
nowMs = Date.now(),
|
|
308
312
|
limit = DEFAULT_CANDIDATE_FEED_LIMIT,
|
|
309
313
|
}) {
|
|
@@ -315,12 +319,18 @@ export function buildCandidateFeed({
|
|
|
315
319
|
|
|
316
320
|
const candidates = candidateMemberships
|
|
317
321
|
.filter((membership) => membership?.status === 'active' && membership.membershipId !== viewerMembership.membershipId)
|
|
318
|
-
.map((membership) => {
|
|
322
|
+
.map((membership) => ({
|
|
323
|
+
membership,
|
|
324
|
+
candidatePresence: getPresence(membership.agentId),
|
|
325
|
+
}))
|
|
326
|
+
.filter(({ candidatePresence }) => candidatePresence?.online === true)
|
|
327
|
+
.map(({ membership, candidatePresence }) => {
|
|
319
328
|
const opportunity = projectCandidateOpportunity({
|
|
320
329
|
world,
|
|
321
330
|
viewerProfile,
|
|
322
331
|
candidateMembership: membership,
|
|
323
332
|
candidateAgent: getAgent(membership.agentId),
|
|
333
|
+
candidatePresence,
|
|
324
334
|
expiresAt,
|
|
325
335
|
});
|
|
326
336
|
|
|
@@ -12,6 +12,24 @@ function normalizeStringList(values = []) {
|
|
|
12
12
|
return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function normalizeCandidateSource(value) {
|
|
16
|
+
const normalized = normalizeText(value, null);
|
|
17
|
+
if (!normalized) return null;
|
|
18
|
+
if (
|
|
19
|
+
normalized === 'active_memberships'
|
|
20
|
+
|| normalized === 'world_members'
|
|
21
|
+
|| normalized === 'search_results'
|
|
22
|
+
) {
|
|
23
|
+
return 'active_memberships_online';
|
|
24
|
+
}
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function normalizeCandidateSources(values = []) {
|
|
29
|
+
if (!Array.isArray(values)) return [];
|
|
30
|
+
return [...new Set(values.map((value) => normalizeCandidateSource(value)).filter(Boolean))];
|
|
31
|
+
}
|
|
32
|
+
|
|
15
33
|
function normalizeWorldEligibility(value, fallback = 'active') {
|
|
16
34
|
const normalized = normalizeText(value, fallback);
|
|
17
35
|
if (normalized === 'joined') return 'joined';
|
|
@@ -188,7 +206,7 @@ export function normalizeWorldManifest(manifest = {}, index = 0) {
|
|
|
188
206
|
mode: normalizeText(manifest.matching?.mode, 'manual_review'),
|
|
189
207
|
cadence: normalizeText(manifest.matching?.cadence, 'on_demand'),
|
|
190
208
|
strategySummary: normalizeText(manifest.matching?.strategySummary, null),
|
|
191
|
-
candidateSources:
|
|
209
|
+
candidateSources: normalizeCandidateSources(manifest.matching?.candidateSources),
|
|
192
210
|
},
|
|
193
211
|
sessionTemplate: {
|
|
194
212
|
mode: normalizeText(manifest.sessionTemplate?.mode, 'a2a'),
|
|
@@ -388,6 +388,7 @@ function normalizeCandidate(candidate = {}, index = 0) {
|
|
|
388
388
|
candidateId: normalizeText(candidate.candidateId, `candidate_${index + 1}`),
|
|
389
389
|
worldId: normalizeText(candidate.worldId, 'unknown-world'),
|
|
390
390
|
sourceMembershipId: normalizeText(candidate.sourceMembershipId, null),
|
|
391
|
+
online: candidate.online === true,
|
|
391
392
|
targetAgentId,
|
|
392
393
|
requestChat,
|
|
393
394
|
profileSummary: normalizeCandidateProfileSummary(candidate.profileSummary),
|
|
@@ -420,7 +421,7 @@ function normalizeCandidateFeedResponse(payload = {}, { worldId = null, agentId
|
|
|
420
421
|
payload.nextAction,
|
|
421
422
|
candidates.length > 0 ? 'review_candidates_then_request_chat' : 'wait_for_more_candidates',
|
|
422
423
|
),
|
|
423
|
-
candidateSource: normalizeText(payload.candidateSource, '
|
|
424
|
+
candidateSource: normalizeText(payload.candidateSource, 'active_memberships_online'),
|
|
424
425
|
candidateModel: payload.candidateModel && typeof payload.candidateModel === 'object' ? payload.candidateModel : {},
|
|
425
426
|
strategy: payload.strategy && typeof payload.strategy === 'object' ? payload.strategy : {},
|
|
426
427
|
limit: normalizeInteger(payload.limit, candidates.length),
|
|
@@ -949,6 +950,7 @@ export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail
|
|
|
949
950
|
.map((signal) => sentenceCase(signal.summary, ''))
|
|
950
951
|
.filter(Boolean);
|
|
951
952
|
const deliveryReasonSummary = sentenceCase(candidate.deliveryReason.summary, '');
|
|
953
|
+
const availabilitySummary = candidate.online === true ? 'Online now.' : 'Currently offline.';
|
|
952
954
|
const scoreSummary = candidate.score == null
|
|
953
955
|
? null
|
|
954
956
|
: `Score ${candidate.score}${candidate.rank == null ? '' : `, rank ${candidate.rank}`}.`;
|
|
@@ -958,12 +960,14 @@ export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail
|
|
|
958
960
|
optionalFieldSummary.length > 0 ? `Optional context: ${optionalFieldSummary.join('; ')}.` : null,
|
|
959
961
|
compatibilitySummary.length > 0 ? compatibilitySummary.join(' ') : null,
|
|
960
962
|
deliveryReasonSummary || null,
|
|
963
|
+
availabilitySummary,
|
|
961
964
|
scoreSummary,
|
|
962
965
|
].filter(Boolean).join(' ');
|
|
963
966
|
|
|
964
967
|
return {
|
|
965
968
|
candidateId: candidate.candidateId,
|
|
966
969
|
sourceMembershipId: candidate.sourceMembershipId,
|
|
970
|
+
online: candidate.online === true,
|
|
967
971
|
targetAgentId: candidate.targetAgentId,
|
|
968
972
|
requestChat: candidate.requestChat,
|
|
969
973
|
displayName: name,
|
|
@@ -982,11 +986,11 @@ export function buildCandidateDeliverySummary(candidateFeed = {}, { worldDetail
|
|
|
982
986
|
const totalCandidateCount = Math.max(normalizedFeed.totalCandidates, deliveredCandidateCount);
|
|
983
987
|
const remainingCandidateCount = Math.max(totalCandidateCount - deliveredCandidateCount, 0);
|
|
984
988
|
const heading = deliveredCandidateCount > 0
|
|
985
|
-
? `${displayName} has ${deliveredCandidateCount} candidate profile ${deliveredCandidateCount === 1 ? 'summary' : 'summaries'} ready for review now.`
|
|
986
|
-
: `No candidate profile summaries are ready for review in ${displayName} yet.`;
|
|
989
|
+
? `${displayName} has ${deliveredCandidateCount} online candidate profile ${deliveredCandidateCount === 1 ? 'summary' : 'summaries'} ready for review now.`
|
|
990
|
+
: `No online candidate profile summaries are ready for review in ${displayName} yet.`;
|
|
987
991
|
const promptBody = deliveredCandidateCount > 0
|
|
988
992
|
? candidateSummaries.map((summary, index) => buildCandidateDeliverySummaryLine(summary, index)).join('\n\n')
|
|
989
|
-
: 'No candidates are currently available from the active-membership feed.';
|
|
993
|
+
: 'No online candidates are currently available from the active-membership feed.';
|
|
990
994
|
|
|
991
995
|
return {
|
|
992
996
|
worldId: normalizedFeed.worldId,
|
|
@@ -33,7 +33,7 @@ export function createClaworldProductShell({
|
|
|
33
33
|
worldService,
|
|
34
34
|
membershipService,
|
|
35
35
|
});
|
|
36
|
-
const matchmakingService = createMatchmakingService({ worldService, worldAuthorizationService, store });
|
|
36
|
+
const matchmakingService = createMatchmakingService({ worldService, worldAuthorizationService, store, presence });
|
|
37
37
|
const searchService = createWorldSearchService({ worldService, worldAuthorizationService, store, presence });
|
|
38
38
|
const worldAdminService = createWorldAdminService({ worldService, worldAuthorizationService, store });
|
|
39
39
|
const chatRequestService = createChatRequestService({
|
|
@@ -217,7 +217,14 @@ function buildViewerContext({ world, membershipStore, normalizedAgentId, worldAu
|
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
function buildBaseFeed({
|
|
220
|
+
function buildBaseFeed({
|
|
221
|
+
world,
|
|
222
|
+
membershipStore,
|
|
223
|
+
normalizedAgentId,
|
|
224
|
+
limit,
|
|
225
|
+
worldAuthorizationService,
|
|
226
|
+
resolvePresence,
|
|
227
|
+
}) {
|
|
221
228
|
const { viewerAgent, viewerMembership } = buildViewerContext({
|
|
222
229
|
world,
|
|
223
230
|
membershipStore,
|
|
@@ -236,6 +243,7 @@ function buildBaseFeed({ world, membershipStore, normalizedAgentId, limit, world
|
|
|
236
243
|
viewerAgent,
|
|
237
244
|
candidateMemberships: activeMemberships,
|
|
238
245
|
getAgent: (candidateAgentId) => membershipStore.getAgent(candidateAgentId),
|
|
246
|
+
getPresence: (candidateAgentId) => resolvePresence(candidateAgentId),
|
|
239
247
|
nowMs,
|
|
240
248
|
limit: activeMemberships.length,
|
|
241
249
|
});
|
|
@@ -248,13 +256,21 @@ function buildBaseFeed({ world, membershipStore, normalizedAgentId, limit, world
|
|
|
248
256
|
};
|
|
249
257
|
}
|
|
250
258
|
|
|
251
|
-
function buildDatingDemoFeed({
|
|
259
|
+
function buildDatingDemoFeed({
|
|
260
|
+
world,
|
|
261
|
+
membershipStore,
|
|
262
|
+
normalizedAgentId,
|
|
263
|
+
limit,
|
|
264
|
+
worldAuthorizationService,
|
|
265
|
+
resolvePresence,
|
|
266
|
+
}) {
|
|
252
267
|
const { viewerMembership, activeMemberships, normalizedLimit, baseFeed } = buildBaseFeed({
|
|
253
268
|
world,
|
|
254
269
|
membershipStore,
|
|
255
270
|
normalizedAgentId,
|
|
256
271
|
limit,
|
|
257
272
|
worldAuthorizationService,
|
|
273
|
+
resolvePresence,
|
|
258
274
|
});
|
|
259
275
|
const membershipById = new Map(activeMemberships.map((membership) => [membership.membershipId, membership]));
|
|
260
276
|
const rankedCandidates = baseFeed.candidates
|
|
@@ -278,19 +294,35 @@ function buildDatingDemoFeed({ world, membershipStore, normalizedAgentId, limit,
|
|
|
278
294
|
...baseFeed,
|
|
279
295
|
agentId: normalizedAgentId,
|
|
280
296
|
limit: normalizedLimit,
|
|
281
|
-
candidateSource: '
|
|
297
|
+
candidateSource: 'active_memberships_online',
|
|
282
298
|
strategy: buildStrategy(world),
|
|
283
299
|
totalCandidates: rankedCandidates.length,
|
|
284
300
|
candidates,
|
|
285
301
|
};
|
|
286
302
|
}
|
|
287
303
|
|
|
288
|
-
export function createMatchmakingService({
|
|
304
|
+
export function createMatchmakingService({
|
|
305
|
+
worldService,
|
|
306
|
+
worldAuthorizationService,
|
|
307
|
+
store = null,
|
|
308
|
+
presence = null,
|
|
309
|
+
} = {}) {
|
|
289
310
|
function assertStore() {
|
|
290
311
|
if (!store) throw createConfigurationError();
|
|
291
312
|
return store;
|
|
292
313
|
}
|
|
293
314
|
|
|
315
|
+
function resolvePresence(agentId) {
|
|
316
|
+
if (!presence) {
|
|
317
|
+
return {
|
|
318
|
+
online: true,
|
|
319
|
+
connectedAt: null,
|
|
320
|
+
lastHeartbeatAt: null,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
return presence.getPresence(agentId);
|
|
324
|
+
}
|
|
325
|
+
|
|
294
326
|
return {
|
|
295
327
|
describeStrategy(worldId) {
|
|
296
328
|
const world = worldService.requireWorld(worldId);
|
|
@@ -312,6 +344,7 @@ export function createMatchmakingService({ worldService, worldAuthorizationServi
|
|
|
312
344
|
normalizedAgentId,
|
|
313
345
|
limit,
|
|
314
346
|
worldAuthorizationService,
|
|
347
|
+
resolvePresence,
|
|
315
348
|
});
|
|
316
349
|
}
|
|
317
350
|
|
|
@@ -321,13 +354,14 @@ export function createMatchmakingService({ worldService, worldAuthorizationServi
|
|
|
321
354
|
normalizedAgentId,
|
|
322
355
|
limit,
|
|
323
356
|
worldAuthorizationService,
|
|
357
|
+
resolvePresence,
|
|
324
358
|
});
|
|
325
359
|
|
|
326
360
|
return {
|
|
327
361
|
...baseFeed,
|
|
328
362
|
agentId: normalizedAgentId,
|
|
329
363
|
limit: normalizedLimit,
|
|
330
|
-
candidateSource: '
|
|
364
|
+
candidateSource: 'active_memberships_online',
|
|
331
365
|
strategy: buildStrategy(world),
|
|
332
366
|
totalCandidates: baseFeed.candidates.length,
|
|
333
367
|
candidates: baseFeed.candidates.slice(0, normalizedLimit),
|
|
@@ -267,13 +267,20 @@ function projectKickoff(kickoff = {}) {
|
|
|
267
267
|
return {
|
|
268
268
|
status: normalizeText(kickoff.status, 'skipped'),
|
|
269
269
|
deliveredAt: normalizeText(kickoff.deliveredAt, null),
|
|
270
|
+
relaySessionPreparedAt: normalizeText(kickoff.relaySessionPreparedAt, null),
|
|
271
|
+
acceptedRoundPreparedAt: normalizeText(kickoff.acceptedRoundPreparedAt, null),
|
|
272
|
+
senderKickoffDeliveredAt: normalizeText(kickoff.senderKickoffDeliveredAt, normalizeText(kickoff.deliveredAt, null)),
|
|
273
|
+
openerAcceptedAt: normalizeText(kickoff.openerAcceptedAt, null),
|
|
274
|
+
openerDeliveredAt: normalizeText(kickoff.openerDeliveredAt, null),
|
|
275
|
+
liveChatEstablishedAt: normalizeText(kickoff.liveChatEstablishedAt, null),
|
|
270
276
|
reason: normalizeText(kickoff.reason, null),
|
|
271
277
|
};
|
|
272
278
|
}
|
|
273
279
|
|
|
274
280
|
function resolveAcceptNextAction(kickoff) {
|
|
275
281
|
const kickoffStatus = kickoff?.status || 'skipped';
|
|
276
|
-
if (kickoffStatus === '
|
|
282
|
+
if (kickoffStatus === 'established') return 'runtime_owns_live_conversation';
|
|
283
|
+
if (kickoffStatus === 'sent') return 'wait_for_sender_opener_delivery';
|
|
277
284
|
if (kickoffStatus === 'failed') return 'backend_kickoff_failed';
|
|
278
285
|
return 'chat_request_accepted_without_opening_message';
|
|
279
286
|
}
|
|
@@ -239,8 +239,8 @@ function buildMatchingStrategy(entryProfileSchema) {
|
|
|
239
239
|
mode: 'profile_overlap',
|
|
240
240
|
cadence: 'on_demand',
|
|
241
241
|
strategySummary:
|
|
242
|
-
`Rank world members by overlap on ${entryProfileSchema.searchableFieldIds.join(', ')}, deliver candidate summaries first, and let members request_chat after review.`,
|
|
243
|
-
candidateSources: ['
|
|
242
|
+
`Rank active online world members by overlap on ${entryProfileSchema.searchableFieldIds.join(', ')}, deliver candidate summaries first, and let members request_chat after review.`,
|
|
243
|
+
candidateSources: ['active_memberships_online'],
|
|
244
244
|
};
|
|
245
245
|
}
|
|
246
246
|
|