@xfxstudio/claworld 0.2.13 → 0.2.14
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 +4 -4
- package/index.js +0 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/claworld-help/SKILL.md +19 -27
- package/skills/claworld-join-and-chat/SKILL.md +9 -9
- package/src/openclaw/index.js +0 -3
- package/src/openclaw/plugin/account-identity.js +0 -1
- package/src/openclaw/plugin/claworld-channel-plugin.js +8 -253
- package/src/openclaw/plugin/managed-config.js +1 -7
- package/src/openclaw/plugin/onboarding.js +1 -1
- package/src/openclaw/plugin/register.js +183 -232
- package/src/openclaw/plugin/relay-client.js +8 -5
- package/src/openclaw/runtime/product-shell-helper.js +11 -364
- package/src/openclaw/runtime/tool-contracts.js +0 -182
- package/src/openclaw/runtime/tool-inventory.js +4 -27
- package/src/lib/agent-profile.js +0 -74
- package/src/lib/http-auth.js +0 -151
- package/src/lib/policy.js +0 -114
- package/src/openclaw/installer/constants.js +0 -14
- package/src/product-shell/agent-cards/card-routes.js +0 -64
- package/src/product-shell/agent-cards/card-service.js +0 -287
- package/src/product-shell/agent-cards/spec-builder.js +0 -167
- package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
- package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
- package/src/product-shell/agent-cards/svg-renderer.js +0 -325
- package/src/product-shell/agent-cards/template-registry.js +0 -131
- package/src/product-shell/catalog/default-world-catalog.js +0 -38
- package/src/product-shell/contracts/candidate-feed.js +0 -393
- package/src/product-shell/contracts/world-manifest.js +0 -369
- package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
- package/src/product-shell/feedback/feedback-contract.js +0 -13
- package/src/product-shell/feedback/feedback-routes.js +0 -98
- package/src/product-shell/feedback/feedback-service.js +0 -252
- package/src/product-shell/index.js +0 -212
- package/src/product-shell/matching/matchmaking-service.js +0 -395
- package/src/product-shell/membership/membership-service.js +0 -284
- package/src/product-shell/onboarding/onboarding-routes.js +0 -37
- package/src/product-shell/onboarding/onboarding-service.js +0 -222
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
- package/src/product-shell/profile/profile-service.js +0 -142
- package/src/product-shell/profile/public-identity-routes.js +0 -160
- package/src/product-shell/profile/public-identity-service.js +0 -192
- package/src/product-shell/search/search-service.js +0 -393
- package/src/product-shell/social/chat-request-approval-policy.js +0 -332
- package/src/product-shell/social/chat-request-routes.js +0 -130
- package/src/product-shell/social/chat-request-service.js +0 -723
- package/src/product-shell/social/friend-routes.js +0 -82
- package/src/product-shell/social/friend-service.js +0 -557
- package/src/product-shell/social/social-routes.js +0 -21
- package/src/product-shell/social/social-service.js +0 -136
- package/src/product-shell/worlds/world-admin-service.js +0 -486
- package/src/product-shell/worlds/world-authorization.js +0 -136
- package/src/product-shell/worlds/world-broadcast-service.js +0 -296
- package/src/product-shell/worlds/world-routes.js +0 -403
- package/src/product-shell/worlds/world-service.js +0 -89
- package/src/product-shell/worlds/world-text.js +0 -75
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
import { authenticateAppTokenRequest, resolveAuthenticatedAgentId } from '../../lib/http-auth.js';
|
|
2
|
-
import {
|
|
3
|
-
buildCandidateDeliverySummary,
|
|
4
|
-
buildResolvedWorldJoinOrchestration,
|
|
5
|
-
buildWorldSelectionPrompt,
|
|
6
|
-
} from '../contracts/world-orchestration.js';
|
|
7
|
-
|
|
8
|
-
function sendWorldError(res, error) {
|
|
9
|
-
const status = Number.isInteger(error?.status) ? error.status : 500;
|
|
10
|
-
if (error?.responseBody && typeof error.responseBody === 'object') {
|
|
11
|
-
return res.status(status).json(error.responseBody);
|
|
12
|
-
}
|
|
13
|
-
const code = typeof error?.code === 'string' ? error.code : 'internal_error';
|
|
14
|
-
return res.status(status).json({ error: code, message: error?.message || code });
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function normalizePositiveInteger(value, fallback) {
|
|
18
|
-
const parsed = Number(value);
|
|
19
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
20
|
-
return Math.max(1, Math.trunc(parsed));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function normalizeWorldListSort(value) {
|
|
24
|
-
const normalized = String(value || '').trim().toLowerCase();
|
|
25
|
-
if (normalized === 'latest') return 'latest';
|
|
26
|
-
return 'hot';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function resolveWorldTimestamp(item = {}) {
|
|
30
|
-
const value = Date.parse(item.updatedAt || item.createdAt || '');
|
|
31
|
-
return Number.isFinite(value) ? value : 0;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function buildWorldDirectoryPayload(worldService, membershipService, query = {}) {
|
|
35
|
-
const requestedLimit = normalizePositiveInteger(query.limit, 10);
|
|
36
|
-
const limit = Math.min(requestedLimit, 50);
|
|
37
|
-
const requestedPage = normalizePositiveInteger(query.page, 1);
|
|
38
|
-
const sort = normalizeWorldListSort(query.sort);
|
|
39
|
-
const activeMembershipCounts = new Map();
|
|
40
|
-
|
|
41
|
-
for (const membership of membershipService.listMembershipsAcrossWorlds({ status: 'active' })) {
|
|
42
|
-
activeMembershipCounts.set(
|
|
43
|
-
membership.worldId,
|
|
44
|
-
(activeMembershipCounts.get(membership.worldId) || 0) + 1,
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const items = worldService.listWorlds().map((world) => {
|
|
49
|
-
const hotness = activeMembershipCounts.get(world.worldId) || 0;
|
|
50
|
-
return {
|
|
51
|
-
...world,
|
|
52
|
-
hotness,
|
|
53
|
-
activatedMemberCount: hotness,
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const sortedItems = [...items].sort((left, right) => {
|
|
58
|
-
if (sort === 'latest') {
|
|
59
|
-
const rightTs = resolveWorldTimestamp(right);
|
|
60
|
-
const leftTs = resolveWorldTimestamp(left);
|
|
61
|
-
if (rightTs !== leftTs) return rightTs - leftTs;
|
|
62
|
-
return String(left.displayName || '').localeCompare(String(right.displayName || ''));
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (right.hotness !== left.hotness) return right.hotness - left.hotness;
|
|
66
|
-
return String(left.displayName || '').localeCompare(String(right.displayName || ''));
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const totalCount = sortedItems.length;
|
|
70
|
-
const totalPages = totalCount === 0 ? 0 : Math.ceil(totalCount / limit);
|
|
71
|
-
const page = totalPages === 0 ? 1 : Math.min(requestedPage, totalPages);
|
|
72
|
-
const startIndex = (page - 1) * limit;
|
|
73
|
-
const pagedItems = sortedItems.slice(startIndex, startIndex + limit);
|
|
74
|
-
|
|
75
|
-
const payload = {
|
|
76
|
-
items: pagedItems,
|
|
77
|
-
pagination: {
|
|
78
|
-
page,
|
|
79
|
-
totalPages,
|
|
80
|
-
totalCount,
|
|
81
|
-
},
|
|
82
|
-
sort,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
...payload,
|
|
87
|
-
orchestration: buildWorldSelectionPrompt({
|
|
88
|
-
...payload,
|
|
89
|
-
recommendedWorldId: pagedItems[0]?.worldId || null,
|
|
90
|
-
}),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function registerWorldRoutes(
|
|
95
|
-
app,
|
|
96
|
-
{
|
|
97
|
-
productShell,
|
|
98
|
-
store,
|
|
99
|
-
worldService,
|
|
100
|
-
membershipService,
|
|
101
|
-
matchmakingService,
|
|
102
|
-
searchService,
|
|
103
|
-
worldBroadcastService,
|
|
104
|
-
worldAdminService,
|
|
105
|
-
worldConversationOrchestrator,
|
|
106
|
-
},
|
|
107
|
-
) {
|
|
108
|
-
function resolveAgentIdentity(req, res, { providedAgentId = null, fieldName = 'agentId', required = true } = {}) {
|
|
109
|
-
const result = resolveAuthenticatedAgentId({
|
|
110
|
-
store,
|
|
111
|
-
req,
|
|
112
|
-
providedAgentId,
|
|
113
|
-
fieldName,
|
|
114
|
-
});
|
|
115
|
-
if (!result.ok) {
|
|
116
|
-
res.status(result.status).json(result.body);
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
if (!result.agentId) {
|
|
120
|
-
if (!required) return null;
|
|
121
|
-
res.status(400).json({
|
|
122
|
-
error: 'invalid_agent',
|
|
123
|
-
field: fieldName,
|
|
124
|
-
message: `${fieldName} is required`,
|
|
125
|
-
});
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
return result.agentId;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function resolveBroadcastSender(req, res) {
|
|
132
|
-
const auth = authenticateAppTokenRequest({ store, req });
|
|
133
|
-
if (!auth.present) {
|
|
134
|
-
res.status(401).json({
|
|
135
|
-
error: 'not_authenticated',
|
|
136
|
-
reason: 'credential_required',
|
|
137
|
-
});
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
if (!auth.ok) {
|
|
141
|
-
res.status(401).json(auth.error);
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const explicitAgentId = String(req.body?.agentId || req.body?.senderAgentId || '').trim() || null;
|
|
146
|
-
if (explicitAgentId && explicitAgentId !== auth.agent.agentId) {
|
|
147
|
-
res.status(403).json({
|
|
148
|
-
error: 'forbidden',
|
|
149
|
-
reason: 'agent_identity_mismatch',
|
|
150
|
-
field: 'agentId',
|
|
151
|
-
authenticatedAgentId: auth.agent.agentId,
|
|
152
|
-
providedAgentId: explicitAgentId,
|
|
153
|
-
});
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return auth.agent.agentId;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
app.get('/v1/meta/product-shell', (_req, res) => {
|
|
161
|
-
res.json(productShell.describe());
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
app.get('/v1/worlds', (req, res) => {
|
|
165
|
-
res.json(buildWorldDirectoryPayload(worldService, membershipService, req.query));
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
app.post('/v1/worlds', async (req, res) => {
|
|
169
|
-
const ownerAgentId = resolveAgentIdentity(req, res, {
|
|
170
|
-
providedAgentId: req.body?.agentId || req.body?.creatorAgentId,
|
|
171
|
-
fieldName: 'agentId',
|
|
172
|
-
});
|
|
173
|
-
if (!ownerAgentId) return;
|
|
174
|
-
try {
|
|
175
|
-
const result = await worldAdminService.createWorld({
|
|
176
|
-
ownerAgentId,
|
|
177
|
-
displayName: req.body?.displayName,
|
|
178
|
-
worldContextText: req.body?.worldContextText,
|
|
179
|
-
enabled: req.body?.enabled,
|
|
180
|
-
});
|
|
181
|
-
res.status(201).json(result);
|
|
182
|
-
} catch (error) {
|
|
183
|
-
sendWorldError(res, error);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
app.get('/v1/worlds/:worldId', (req, res) => {
|
|
188
|
-
try {
|
|
189
|
-
const detail = worldService.describeWorldDetail(req.params.worldId);
|
|
190
|
-
res.json(detail);
|
|
191
|
-
} catch (error) {
|
|
192
|
-
sendWorldError(res, error);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
app.post('/v1/worlds/:worldId/search', (req, res) => {
|
|
197
|
-
const agentId = resolveAgentIdentity(req, res, {
|
|
198
|
-
providedAgentId: req.body?.agentId,
|
|
199
|
-
fieldName: 'agentId',
|
|
200
|
-
});
|
|
201
|
-
if (!agentId) return;
|
|
202
|
-
try {
|
|
203
|
-
const result = searchService.searchWorld({
|
|
204
|
-
worldId: req.params.worldId,
|
|
205
|
-
agentId,
|
|
206
|
-
query: req.body?.query || {},
|
|
207
|
-
limit: req.body?.limit || null,
|
|
208
|
-
});
|
|
209
|
-
res.json(result);
|
|
210
|
-
} catch (error) {
|
|
211
|
-
sendWorldError(res, error);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
app.post('/v1/worlds/:worldId/broadcast', async (req, res) => {
|
|
216
|
-
const senderAgentId = resolveBroadcastSender(req, res);
|
|
217
|
-
if (!senderAgentId) return;
|
|
218
|
-
try {
|
|
219
|
-
const result = await worldBroadcastService.broadcastWorld({
|
|
220
|
-
worldId: req.params.worldId,
|
|
221
|
-
senderAgentId,
|
|
222
|
-
payload: req.body?.payload,
|
|
223
|
-
audience: req.body?.audience,
|
|
224
|
-
excludeSelf: req.body?.excludeSelf,
|
|
225
|
-
});
|
|
226
|
-
res.json(result);
|
|
227
|
-
} catch (error) {
|
|
228
|
-
sendWorldError(res, error);
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
app.get('/v1/worlds/:worldId/candidates', (req, res) => {
|
|
233
|
-
const agentId = resolveAgentIdentity(req, res, {
|
|
234
|
-
providedAgentId: req.query.agentId || null,
|
|
235
|
-
fieldName: 'agentId',
|
|
236
|
-
});
|
|
237
|
-
if (!agentId) return;
|
|
238
|
-
try {
|
|
239
|
-
const result = matchmakingService.listCandidateFeed({
|
|
240
|
-
worldId: req.params.worldId,
|
|
241
|
-
agentId,
|
|
242
|
-
limit: req.query.limit || null,
|
|
243
|
-
});
|
|
244
|
-
const worldDetail = worldService.describeWorldDetail(req.params.worldId);
|
|
245
|
-
res.json({
|
|
246
|
-
...result,
|
|
247
|
-
candidateDelivery: buildCandidateDeliverySummary(result, {
|
|
248
|
-
worldDetail,
|
|
249
|
-
limit: req.query.limit || result.limit || null,
|
|
250
|
-
}),
|
|
251
|
-
});
|
|
252
|
-
} catch (error) {
|
|
253
|
-
sendWorldError(res, error);
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
app.post('/v1/worlds/:worldId/join', async (req, res) => {
|
|
258
|
-
const agentId = resolveAgentIdentity(req, res, {
|
|
259
|
-
providedAgentId: req.body?.agentId,
|
|
260
|
-
fieldName: 'agentId',
|
|
261
|
-
});
|
|
262
|
-
if (!agentId) return;
|
|
263
|
-
try {
|
|
264
|
-
const result = await membershipService.joinWorld({
|
|
265
|
-
worldId: req.params.worldId,
|
|
266
|
-
agentId,
|
|
267
|
-
participantContextText: req.body?.participantContextText,
|
|
268
|
-
});
|
|
269
|
-
const worldDetail = worldService.describeWorldDetail(req.params.worldId);
|
|
270
|
-
const candidateFeed = matchmakingService.listCandidateFeed({
|
|
271
|
-
worldId: req.params.worldId,
|
|
272
|
-
agentId,
|
|
273
|
-
limit: req.body?.candidateLimit || null,
|
|
274
|
-
});
|
|
275
|
-
const candidateDelivery = buildCandidateDeliverySummary(candidateFeed, {
|
|
276
|
-
worldDetail,
|
|
277
|
-
limit: req.body?.candidateLimit || candidateFeed.limit || null,
|
|
278
|
-
});
|
|
279
|
-
res.status(result.created ? 201 : 200).json({
|
|
280
|
-
status: result.status,
|
|
281
|
-
worldId: req.params.worldId,
|
|
282
|
-
membershipStatus: result.membershipStatus,
|
|
283
|
-
normalizedProfile: result.normalizedProfile,
|
|
284
|
-
membership: result.membership,
|
|
285
|
-
nextAction: result.nextAction,
|
|
286
|
-
nextStageSummary: result.nextStageSummary,
|
|
287
|
-
candidateFeed: {
|
|
288
|
-
...candidateFeed,
|
|
289
|
-
candidateDelivery,
|
|
290
|
-
},
|
|
291
|
-
candidateDelivery,
|
|
292
|
-
orchestration: buildResolvedWorldJoinOrchestration({
|
|
293
|
-
joinResult: result,
|
|
294
|
-
candidateDelivery,
|
|
295
|
-
}) || result.orchestration || null,
|
|
296
|
-
});
|
|
297
|
-
} catch (error) {
|
|
298
|
-
sendWorldError(res, error);
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
app.get('/v1/worlds/:worldId/memberships', (req, res) => {
|
|
303
|
-
const agentId = resolveAgentIdentity(req, res, {
|
|
304
|
-
providedAgentId: req.query.agentId || null,
|
|
305
|
-
fieldName: 'agentId',
|
|
306
|
-
required: false,
|
|
307
|
-
});
|
|
308
|
-
try {
|
|
309
|
-
const items = membershipService.listMemberships({
|
|
310
|
-
worldId: req.params.worldId,
|
|
311
|
-
agentId,
|
|
312
|
-
status: req.query.status || null,
|
|
313
|
-
});
|
|
314
|
-
res.json({ items });
|
|
315
|
-
} catch (error) {
|
|
316
|
-
sendWorldError(res, error);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
app.post('/v1/worlds/:worldId/memberships', async (req, res) => {
|
|
321
|
-
const agentId = resolveAgentIdentity(req, res, {
|
|
322
|
-
providedAgentId: req.body?.agentId,
|
|
323
|
-
fieldName: 'agentId',
|
|
324
|
-
});
|
|
325
|
-
if (!agentId) return;
|
|
326
|
-
try {
|
|
327
|
-
const result = await membershipService.createMembership({
|
|
328
|
-
worldId: req.params.worldId,
|
|
329
|
-
agentId,
|
|
330
|
-
participantContextText: req.body?.participantContextText,
|
|
331
|
-
});
|
|
332
|
-
res.status(result.created ? 201 : 200).json(result.membership);
|
|
333
|
-
} catch (error) {
|
|
334
|
-
sendWorldError(res, error);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
app.post('/v1/worlds/:worldId/conversation-preview', (req, res) => {
|
|
339
|
-
try {
|
|
340
|
-
const result = worldConversationOrchestrator.previewConversation({
|
|
341
|
-
worldId: req.params.worldId,
|
|
342
|
-
conversationKey: req.body?.conversationKey,
|
|
343
|
-
});
|
|
344
|
-
res.json(result);
|
|
345
|
-
} catch (error) {
|
|
346
|
-
sendWorldError(res, error);
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
app.get('/v1/moderation/worlds', (req, res) => {
|
|
351
|
-
const actorAgentId = resolveAgentIdentity(req, res, {
|
|
352
|
-
providedAgentId: req.query.agentId || null,
|
|
353
|
-
fieldName: 'agentId',
|
|
354
|
-
});
|
|
355
|
-
if (!actorAgentId) return;
|
|
356
|
-
try {
|
|
357
|
-
const items = worldAdminService.listManagedWorlds({
|
|
358
|
-
actorAgentId,
|
|
359
|
-
includeDisabled: req.query.includeDisabled !== 'false',
|
|
360
|
-
});
|
|
361
|
-
res.json({ items });
|
|
362
|
-
} catch (error) {
|
|
363
|
-
sendWorldError(res, error);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
app.get('/v1/moderation/worlds/:worldId', (req, res) => {
|
|
368
|
-
const actorAgentId = resolveAgentIdentity(req, res, {
|
|
369
|
-
providedAgentId: req.query.agentId || null,
|
|
370
|
-
fieldName: 'agentId',
|
|
371
|
-
});
|
|
372
|
-
if (!actorAgentId) return;
|
|
373
|
-
try {
|
|
374
|
-
const result = worldAdminService.getManagedWorld({
|
|
375
|
-
actorAgentId,
|
|
376
|
-
worldId: req.params.worldId,
|
|
377
|
-
});
|
|
378
|
-
res.json(result);
|
|
379
|
-
} catch (error) {
|
|
380
|
-
sendWorldError(res, error);
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
app.patch('/v1/moderation/worlds/:worldId', async (req, res) => {
|
|
385
|
-
const actorAgentId = resolveAgentIdentity(req, res, {
|
|
386
|
-
providedAgentId: req.body?.agentId || null,
|
|
387
|
-
fieldName: 'agentId',
|
|
388
|
-
});
|
|
389
|
-
if (!actorAgentId) return;
|
|
390
|
-
try {
|
|
391
|
-
const result = await worldAdminService.manageWorld({
|
|
392
|
-
actorAgentId,
|
|
393
|
-
worldId: req.params.worldId,
|
|
394
|
-
changes: req.body?.changes || null,
|
|
395
|
-
enabled: Object.prototype.hasOwnProperty.call(req.body || {}, 'enabled') ? req.body.enabled : null,
|
|
396
|
-
status: req.body?.status || null,
|
|
397
|
-
});
|
|
398
|
-
res.json(result);
|
|
399
|
-
} catch (error) {
|
|
400
|
-
sendWorldError(res, error);
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
normalizeWorldManifest,
|
|
3
|
-
projectWorldCard,
|
|
4
|
-
projectWorldDetail,
|
|
5
|
-
projectJoinPlan,
|
|
6
|
-
projectConversationWorldContext,
|
|
7
|
-
} from '../contracts/world-manifest.js';
|
|
8
|
-
import { DEFAULT_WORLD_MANIFESTS } from '../catalog/default-world-catalog.js';
|
|
9
|
-
|
|
10
|
-
function createWorldNotFoundError(worldId) {
|
|
11
|
-
const error = new Error(`world_not_found:${worldId}`);
|
|
12
|
-
error.code = 'world_not_found';
|
|
13
|
-
error.status = 404;
|
|
14
|
-
return error;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function createWorldService({ worldCatalog = DEFAULT_WORLD_MANIFESTS, store = null } = {}) {
|
|
18
|
-
const seededWorlds = worldCatalog.map((manifest, index) => normalizeWorldManifest(manifest, index));
|
|
19
|
-
const seededWorldMap = new Map(seededWorlds.map((world) => [world.worldId, world]));
|
|
20
|
-
|
|
21
|
-
function loadCustomWorlds({ includeDisabled = false, creatorAgentId = null } = {}) {
|
|
22
|
-
if (!store || typeof store.listWorldConfigs !== 'function') return [];
|
|
23
|
-
|
|
24
|
-
return store
|
|
25
|
-
.listWorldConfigs({ creatorAgentId })
|
|
26
|
-
.filter((world) => includeDisabled || world.enabled === true)
|
|
27
|
-
.map((world, index) => normalizeWorldManifest(world, seededWorlds.length + index));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function loadWorldMap(options = {}) {
|
|
31
|
-
return new Map(
|
|
32
|
-
[...seededWorlds, ...loadCustomWorlds(options)].map((world) => [world.worldId, world]),
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
listWorlds() {
|
|
38
|
-
return [...seededWorlds, ...loadCustomWorlds()].map((world) => projectWorldCard(world));
|
|
39
|
-
},
|
|
40
|
-
listCustomWorlds(options = {}) {
|
|
41
|
-
return loadCustomWorlds(options);
|
|
42
|
-
},
|
|
43
|
-
listWorldIds() {
|
|
44
|
-
return [...seededWorlds, ...loadCustomWorlds({ includeDisabled: true })].map((world) => world.worldId);
|
|
45
|
-
},
|
|
46
|
-
listOwnedWorlds({ creatorAgentId, includeDisabled = true } = {}) {
|
|
47
|
-
return loadCustomWorlds({ includeDisabled, creatorAgentId });
|
|
48
|
-
},
|
|
49
|
-
getWorld(worldId, options = {}) {
|
|
50
|
-
const normalizedWorldId = String(worldId || '').trim();
|
|
51
|
-
if (!normalizedWorldId) return null;
|
|
52
|
-
if (seededWorldMap.has(normalizedWorldId)) return seededWorldMap.get(normalizedWorldId) || null;
|
|
53
|
-
return loadWorldMap(options).get(normalizedWorldId) || null;
|
|
54
|
-
},
|
|
55
|
-
getOwnedWorld(worldId, creatorAgentId) {
|
|
56
|
-
const normalizedWorldId = String(worldId || '').trim();
|
|
57
|
-
if (!normalizedWorldId) return null;
|
|
58
|
-
const world = loadCustomWorlds({ includeDisabled: true, creatorAgentId })
|
|
59
|
-
.find((entry) => entry.worldId === normalizedWorldId) || null;
|
|
60
|
-
return world;
|
|
61
|
-
},
|
|
62
|
-
requireWorld(worldId, options = {}) {
|
|
63
|
-
const world = this.getWorld(worldId, options);
|
|
64
|
-
if (!world) throw createWorldNotFoundError(worldId);
|
|
65
|
-
return world;
|
|
66
|
-
},
|
|
67
|
-
requireOwnedWorld(worldId, creatorAgentId) {
|
|
68
|
-
const world = this.getOwnedWorld(worldId, creatorAgentId);
|
|
69
|
-
if (!world) throw createWorldNotFoundError(worldId);
|
|
70
|
-
return world;
|
|
71
|
-
},
|
|
72
|
-
describeWorldDetail(worldId) {
|
|
73
|
-
return projectWorldDetail(this.requireWorld(worldId));
|
|
74
|
-
},
|
|
75
|
-
buildJoinPlan(worldId) {
|
|
76
|
-
return projectJoinPlan(this.requireWorld(worldId));
|
|
77
|
-
},
|
|
78
|
-
describeConversationWorldContext(worldId) {
|
|
79
|
-
return projectConversationWorldContext(this.requireWorld(worldId));
|
|
80
|
-
},
|
|
81
|
-
describeCatalog() {
|
|
82
|
-
return {
|
|
83
|
-
worldCount: this.listWorldIds().length,
|
|
84
|
-
worldIds: this.listWorldIds(),
|
|
85
|
-
status: store ? 'seeded_plus_store' : 'seeded_catalog',
|
|
86
|
-
};
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
function normalizeText(value, fallback = null) {
|
|
2
|
-
if (value == null) return fallback;
|
|
3
|
-
const normalized = String(value).trim();
|
|
4
|
-
return normalized || fallback;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
function normalizeStringList(values = []) {
|
|
8
|
-
if (!Array.isArray(values)) return [];
|
|
9
|
-
return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function formatProfileValue(value) {
|
|
13
|
-
if (value == null) return null;
|
|
14
|
-
if (typeof value === 'string') return normalizeText(value, null);
|
|
15
|
-
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
16
|
-
if (Array.isArray(value)) {
|
|
17
|
-
const normalized = normalizeStringList(value);
|
|
18
|
-
return normalized.length > 0 ? normalized.join(', ') : null;
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function buildWorldContextText({
|
|
24
|
-
worldId = null,
|
|
25
|
-
displayName = null,
|
|
26
|
-
summary = null,
|
|
27
|
-
worldContextText = null,
|
|
28
|
-
interactionRules = null,
|
|
29
|
-
prohibitedRules = null,
|
|
30
|
-
} = {}) {
|
|
31
|
-
const explicitWorldContextText = normalizeText(worldContextText, null);
|
|
32
|
-
if (explicitWorldContextText) return explicitWorldContextText;
|
|
33
|
-
|
|
34
|
-
const normalizedWorldId = normalizeText(worldId, null);
|
|
35
|
-
const normalizedDisplayName = normalizeText(displayName, normalizedWorldId);
|
|
36
|
-
const lines = [
|
|
37
|
-
normalizedDisplayName
|
|
38
|
-
? `世界:${normalizedDisplayName}${normalizedWorldId ? ` [${normalizedWorldId}]` : ''}`
|
|
39
|
-
: (normalizedWorldId ? `世界:${normalizedWorldId}` : null),
|
|
40
|
-
normalizeText(summary, null) ? `简介:${normalizeText(summary, null)}` : null,
|
|
41
|
-
normalizeText(interactionRules, null) ? `互动规则:${normalizeText(interactionRules, null)}` : null,
|
|
42
|
-
normalizeText(prohibitedRules, null) ? `禁止事项:${normalizeText(prohibitedRules, null)}` : null,
|
|
43
|
-
].filter(Boolean);
|
|
44
|
-
|
|
45
|
-
return lines.length > 0 ? lines.join('\n') : null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function buildParticipantContextText({
|
|
49
|
-
world = null,
|
|
50
|
-
agent = null,
|
|
51
|
-
participantContextText = null,
|
|
52
|
-
profileSnapshot = null,
|
|
53
|
-
} = {}) {
|
|
54
|
-
const explicitParticipantContextText = normalizeText(participantContextText, null);
|
|
55
|
-
if (explicitParticipantContextText) return explicitParticipantContextText;
|
|
56
|
-
|
|
57
|
-
const normalizedProfileSnapshot = profileSnapshot && typeof profileSnapshot === 'object' && !Array.isArray(profileSnapshot)
|
|
58
|
-
? profileSnapshot
|
|
59
|
-
: {};
|
|
60
|
-
const normalizedProfileText = normalizeText(normalizedProfileSnapshot.participantContextText, null);
|
|
61
|
-
if (normalizedProfileText) return normalizedProfileText;
|
|
62
|
-
|
|
63
|
-
const lines = [
|
|
64
|
-
normalizeText(agent?.displayName, null) ? `名称:${normalizeText(agent.displayName, null)}` : null,
|
|
65
|
-
normalizeText(normalizedProfileSnapshot.headline, null) ? `简介:${normalizeText(normalizedProfileSnapshot.headline, null)}` : null,
|
|
66
|
-
...Object.entries(normalizedProfileSnapshot).map(([fieldId, rawValue]) => {
|
|
67
|
-
if (fieldId === 'headline' || fieldId === 'participantContextText') return null;
|
|
68
|
-
const value = formatProfileValue(rawValue);
|
|
69
|
-
if (!value) return null;
|
|
70
|
-
return `${fieldId}:${value}`;
|
|
71
|
-
}),
|
|
72
|
-
].filter(Boolean);
|
|
73
|
-
|
|
74
|
-
return lines.length > 0 ? lines.join('\n') : null;
|
|
75
|
-
}
|