@xfxstudio/claworld 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +4 -4
  2. package/index.js +0 -1
  3. package/openclaw.plugin.json +1 -97
  4. package/package.json +1 -1
  5. package/skills/claworld-help/SKILL.md +47 -27
  6. package/skills/claworld-join-and-chat/SKILL.md +13 -9
  7. package/src/openclaw/index.js +0 -3
  8. package/src/openclaw/plugin/account-identity.js +0 -1
  9. package/src/openclaw/plugin/claworld-channel-plugin.js +73 -319
  10. package/src/openclaw/plugin/config-schema.js +1 -55
  11. package/src/openclaw/plugin/managed-config.js +1 -42
  12. package/src/openclaw/plugin/onboarding.js +1 -1
  13. package/src/openclaw/plugin/register.js +302 -233
  14. package/src/openclaw/plugin/relay-client.js +9 -6
  15. package/src/openclaw/runtime/product-shell-helper.js +11 -364
  16. package/src/openclaw/runtime/tool-contracts.js +0 -182
  17. package/src/openclaw/runtime/tool-inventory.js +4 -27
  18. package/src/lib/agent-profile.js +0 -74
  19. package/src/lib/http-auth.js +0 -151
  20. package/src/lib/policy.js +0 -114
  21. package/src/openclaw/installer/constants.js +0 -14
  22. package/src/product-shell/agent-cards/card-routes.js +0 -64
  23. package/src/product-shell/agent-cards/card-service.js +0 -287
  24. package/src/product-shell/agent-cards/spec-builder.js +0 -167
  25. package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
  26. package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
  27. package/src/product-shell/agent-cards/svg-renderer.js +0 -325
  28. package/src/product-shell/agent-cards/template-registry.js +0 -131
  29. package/src/product-shell/catalog/default-world-catalog.js +0 -38
  30. package/src/product-shell/contracts/candidate-feed.js +0 -393
  31. package/src/product-shell/contracts/world-manifest.js +0 -369
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
  33. package/src/product-shell/feedback/feedback-contract.js +0 -13
  34. package/src/product-shell/feedback/feedback-routes.js +0 -98
  35. package/src/product-shell/feedback/feedback-service.js +0 -252
  36. package/src/product-shell/index.js +0 -212
  37. package/src/product-shell/matching/matchmaking-service.js +0 -395
  38. package/src/product-shell/membership/membership-service.js +0 -284
  39. package/src/product-shell/onboarding/onboarding-routes.js +0 -37
  40. package/src/product-shell/onboarding/onboarding-service.js +0 -222
  41. package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
  42. package/src/product-shell/profile/profile-service.js +0 -142
  43. package/src/product-shell/profile/public-identity-routes.js +0 -160
  44. package/src/product-shell/profile/public-identity-service.js +0 -192
  45. package/src/product-shell/search/search-service.js +0 -393
  46. package/src/product-shell/social/chat-request-approval-policy.js +0 -332
  47. package/src/product-shell/social/chat-request-routes.js +0 -130
  48. package/src/product-shell/social/chat-request-service.js +0 -723
  49. package/src/product-shell/social/friend-routes.js +0 -82
  50. package/src/product-shell/social/friend-service.js +0 -557
  51. package/src/product-shell/social/social-routes.js +0 -21
  52. package/src/product-shell/social/social-service.js +0 -136
  53. package/src/product-shell/worlds/world-admin-service.js +0 -486
  54. package/src/product-shell/worlds/world-authorization.js +0 -136
  55. package/src/product-shell/worlds/world-broadcast-service.js +0 -296
  56. package/src/product-shell/worlds/world-routes.js +0 -403
  57. package/src/product-shell/worlds/world-service.js +0 -89
  58. package/src/product-shell/worlds/world-text.js +0 -75
@@ -1,136 +0,0 @@
1
- import {
2
- normalizeAgentProfile,
3
- resolveAgentDisplayName,
4
- resolveAgentVisibility,
5
- } from '../../lib/agent-profile.js';
6
- import { parsePublicIdentityDisplay, resolvePublicIdentity } from '../../lib/public-identity.js';
7
-
8
- function normalizeText(value, fallback = null) {
9
- if (value == null) return fallback;
10
- const normalized = String(value).trim();
11
- return normalized || fallback;
12
- }
13
-
14
- function createConfigurationError() {
15
- const error = new Error('social_lookup_store_unavailable');
16
- error.code = 'social_lookup_store_unavailable';
17
- error.status = 500;
18
- return error;
19
- }
20
-
21
- function createInvalidPublicIdentityError(identity) {
22
- const error = new Error('invalid_public_identity');
23
- error.code = 'invalid_public_identity';
24
- error.status = 400;
25
- error.responseBody = {
26
- error: error.code,
27
- message: 'identity must use displayName#code',
28
- identity: normalizeText(identity, null),
29
- fieldErrors: [
30
- {
31
- fieldId: 'identity',
32
- message: 'identity must use displayName#code',
33
- },
34
- ],
35
- };
36
- return error;
37
- }
38
-
39
- function createAgentNotFoundError(identity) {
40
- const error = new Error(`agent_not_found:${identity}`);
41
- error.code = 'agent_not_found';
42
- error.status = 404;
43
- error.responseBody = {
44
- error: error.code,
45
- message: 'no agent found for public identity',
46
- identity,
47
- };
48
- return error;
49
- }
50
-
51
- function createNotDiscoverableError(identity) {
52
- const error = new Error(`not_discoverable:${identity}`);
53
- error.code = 'not_discoverable';
54
- error.status = 403;
55
- error.responseBody = {
56
- error: error.code,
57
- message: 'agent is not discoverable',
58
- identity,
59
- };
60
- return error;
61
- }
62
-
63
- function compareActiveWorlds(left, right) {
64
- const displayNameOrder = String(left.displayName || '').localeCompare(String(right.displayName || ''));
65
- if (displayNameOrder !== 0) return displayNameOrder;
66
- return String(left.worldId || '').localeCompare(String(right.worldId || ''));
67
- }
68
-
69
- function projectActiveWorldSummary(world) {
70
- return {
71
- worldId: world.worldId,
72
- displayName: world.displayName,
73
- summary: world.summary,
74
- category: world.category,
75
- };
76
- }
77
-
78
- export function createSocialService({ worldService, store = null } = {}) {
79
- function assertStore() {
80
- if (!store) throw createConfigurationError();
81
- return store;
82
- }
83
-
84
- return {
85
- lookupAgentByIdentity({ identity } = {}) {
86
- const socialStore = assertStore();
87
- const parsedIdentity = parsePublicIdentityDisplay(identity);
88
- if (!parsedIdentity) {
89
- throw createInvalidPublicIdentityError(identity);
90
- }
91
-
92
- const agent = socialStore
93
- .listAgents()
94
- .find((candidate) => {
95
- const candidateIdentity = resolvePublicIdentity(candidate);
96
- return candidateIdentity.status === 'ready'
97
- && candidateIdentity.code === parsedIdentity.code;
98
- }) || null;
99
- if (!agent) {
100
- throw createAgentNotFoundError(parsedIdentity.identity);
101
- }
102
-
103
- const visibility = resolveAgentVisibility(agent);
104
- if (!visibility.discoverable) {
105
- throw createNotDiscoverableError(parsedIdentity.identity);
106
- }
107
-
108
- const activeWorlds = socialStore
109
- .listMemberships({
110
- agentId: agent.agentId,
111
- status: 'active',
112
- })
113
- .map((membership) => worldService.getWorld(membership.worldId))
114
- .filter(Boolean)
115
- .map((world) => projectActiveWorldSummary(world))
116
- .sort(compareActiveWorlds);
117
-
118
- return {
119
- status: 'found',
120
- publicProfile: {
121
- agentId: agent.agentId,
122
- identity: resolvePublicIdentity(agent).displayIdentity || parsedIdentity.identity,
123
- displayName: resolveAgentDisplayName(agent),
124
- code: resolvePublicIdentity(agent).code,
125
- profile: normalizeAgentProfile(agent.profile),
126
- discoverable: visibility.discoverable,
127
- contactable: visibility.contactable,
128
- },
129
- activeWorlds: {
130
- totalCount: activeWorlds.length,
131
- items: activeWorlds,
132
- },
133
- };
134
- },
135
- };
136
- }
@@ -1,486 +0,0 @@
1
- import { WORLD_ACTIONS, WORLD_ROLES } from './world-authorization.js';
2
- import { buildWorldContextText } from './world-text.js';
3
-
4
- function normalizeText(value, fallback = null) {
5
- if (value == null) return fallback;
6
- const normalized = String(value).trim();
7
- return normalized || fallback;
8
- }
9
-
10
- function normalizeBoolean(value, fallback = false) {
11
- if (typeof value === 'boolean') return value;
12
- return fallback;
13
- }
14
-
15
- const OWNER_WORLD_STATUSES = new Set(['draft', 'enabled', 'paused', 'closed', 'disabled']);
16
-
17
- function normalizeOwnerWorldStatus(value, fallback = null) {
18
- const normalized = normalizeText(value, fallback);
19
- return OWNER_WORLD_STATUSES.has(normalized) ? normalized : fallback;
20
- }
21
-
22
- function inferEnabledFromOwnerWorldStatus(status, fallback = null) {
23
- const normalizedStatus = normalizeOwnerWorldStatus(status, null);
24
- if (!normalizedStatus) return fallback;
25
- return normalizedStatus === 'enabled';
26
- }
27
-
28
- function projectOwnerWorldMetaStatus(status, enabled) {
29
- const normalizedStatus = normalizeOwnerWorldStatus(status, enabled === true ? 'enabled' : 'draft');
30
- switch (normalizedStatus) {
31
- case 'enabled':
32
- return 'creator_enabled';
33
- case 'paused':
34
- return 'creator_paused';
35
- case 'closed':
36
- return 'creator_closed';
37
- case 'disabled':
38
- return 'creator_disabled';
39
- case 'draft':
40
- default:
41
- return 'creator_draft';
42
- }
43
- }
44
-
45
- function summarizeWorldContextText(worldContextText, fallback = null) {
46
- const normalized = normalizeText(worldContextText, null);
47
- if (!normalized) return fallback;
48
- const firstLine = normalized
49
- .split('\n')
50
- .map((line) => line.trim())
51
- .find(Boolean);
52
- return firstLine || fallback;
53
- }
54
-
55
- function slugify(value, fallback = 'world') {
56
- const normalized = normalizeText(value, fallback)
57
- .toLowerCase()
58
- .replace(/[^a-z0-9]+/g, '-')
59
- .replace(/^-+|-+$/g, '');
60
- return normalized || fallback;
61
- }
62
-
63
- function createConfigurationError() {
64
- const error = new Error('world_store_unavailable');
65
- error.code = 'world_store_unavailable';
66
- error.status = 500;
67
- return error;
68
- }
69
-
70
- function createAgentNotFoundError(agentId) {
71
- const error = new Error(`agent_not_found:${agentId}`);
72
- error.code = 'agent_not_found';
73
- error.status = 404;
74
- return error;
75
- }
76
-
77
- function createWorldActionNotAllowedError({
78
- worldId,
79
- agentId,
80
- action,
81
- actorRole = null,
82
- allowedRoles = [],
83
- } = {}) {
84
- const error = new Error(`world_action_not_allowed:${action}:${worldId}:${agentId}`);
85
- error.code = 'world_action_not_allowed';
86
- error.status = 403;
87
- const messageByAction = {
88
- [WORLD_ACTIONS.VIEW_MANAGEMENT]: 'agent does not have permission to access world management',
89
- [WORLD_ACTIONS.MANAGE_WORLD]: 'agent does not have permission to manage this world',
90
- [WORLD_ACTIONS.CHANGE_ENABLED_STATE]: 'only the world owner can enable or disable this world',
91
- };
92
- error.responseBody = {
93
- error: error.code,
94
- message: messageByAction[action] || 'agent does not have permission to manage this world',
95
- worldId,
96
- agentId,
97
- action,
98
- actorRole,
99
- allowedRoles,
100
- };
101
- return error;
102
- }
103
-
104
- function createInvalidWorldRequestError(fieldId, message = `${fieldId} is required`) {
105
- const error = new Error(`invalid_world_request:${fieldId}`);
106
- error.code = 'invalid_world_request';
107
- error.status = 400;
108
- error.responseBody = {
109
- error: error.code,
110
- message: 'world request is invalid',
111
- fieldErrors: [
112
- {
113
- fieldId,
114
- message,
115
- },
116
- ],
117
- };
118
- return error;
119
- }
120
-
121
- function normalizeAgentId(agentId) {
122
- return normalizeText(agentId, null);
123
- }
124
-
125
- function normalizeWorldRole(worldRole, fallback = null) {
126
- const normalized = normalizeText(worldRole, fallback);
127
- return [WORLD_ROLES.OWNER, WORLD_ROLES.MEMBER].includes(normalized) ? normalized : fallback;
128
- }
129
-
130
- function buildDefaultEntryProfileField() {
131
- return {
132
- fieldId: 'participantContextText',
133
- label: 'Entry Profile',
134
- type: 'string',
135
- required: true,
136
- searchable: true,
137
- description: 'Free-form participant profile/context text used for world join, search, and candidate review.',
138
- examples: [],
139
- };
140
- }
141
-
142
- function buildSearchSchema() {
143
- return {
144
- mode: 'profile_overlap_search',
145
- inputFieldIds: ['participantContextText'],
146
- summary:
147
- 'Manual world search over active online members using participantContextText. Candidate feed review is the canonical path before request_chat.',
148
- onlineOnly: true,
149
- defaultLimit: 10,
150
- };
151
- }
152
-
153
- function buildMatchingStrategy() {
154
- return {
155
- mode: 'profile_overlap',
156
- cadence: 'on_demand',
157
- strategySummary:
158
- 'Rank active online world members by overlap on participantContextText, deliver candidate summaries first, and let members request_chat after review.',
159
- candidateSources: ['active_memberships_online'],
160
- };
161
- }
162
-
163
- function buildConversationTemplate(interactionRules, prohibitedRules, { existingConversationTemplate = null } = {}) {
164
- return {
165
- mode: normalizeText(existingConversationTemplate?.mode, 'a2a'),
166
- worldRules: {
167
- openingText: interactionRules,
168
- turnMessageRules: Array.isArray(existingConversationTemplate?.worldRules?.turnMessageRules)
169
- ? existingConversationTemplate.worldRules.turnMessageRules
170
- : [],
171
- convergence: existingConversationTemplate?.worldRules?.convergence || {},
172
- stateChangeMessages: existingConversationTemplate?.worldRules?.stateChangeMessages || {},
173
- },
174
- };
175
- }
176
-
177
- function buildWorldRecord({
178
- worldId,
179
- creatorAgentId,
180
- displayName,
181
- summary,
182
- worldContextText = null,
183
- enabled = true,
184
- status = null,
185
- existingMetrics = null,
186
- } = {}) {
187
- const resolvedStatus = normalizeOwnerWorldStatus(status, enabled ? 'enabled' : 'draft');
188
- const participantContextField = buildDefaultEntryProfileField();
189
- const resolvedWorldContextText = buildWorldContextText({
190
- worldId,
191
- displayName,
192
- summary,
193
- worldContextText,
194
- interactionRules: null,
195
- prohibitedRules: null,
196
- });
197
-
198
- return {
199
- worldId,
200
- slug: slugify(displayName, worldId),
201
- displayName,
202
- summary,
203
- description: resolvedWorldContextText,
204
- category: 'ugc',
205
- lifecycle: 'creator_managed',
206
- tags: ['ugc', 'creator-managed'],
207
- interactionRules: null,
208
- prohibitedRules: null,
209
- worldContextText: resolvedWorldContextText,
210
- joinSchema: {
211
- requiredFields: [participantContextField],
212
- optionalFields: [],
213
- hints: [],
214
- },
215
- searchSchema: buildSearchSchema(),
216
- matching: buildMatchingStrategy(),
217
- conversationTemplate: buildConversationTemplate(null, null),
218
- meta: {
219
- status: projectOwnerWorldMetaStatus(resolvedStatus, enabled),
220
- persistence: 'store',
221
- },
222
- creatorAgentId,
223
- eligibility: 'active',
224
- broadcast: {
225
- enabled: false,
226
- audience: 'members',
227
- replyPolicy: 'zero',
228
- excludeSelf: true,
229
- },
230
- status: resolvedStatus,
231
- enabled,
232
- schemaVersion: 1,
233
- metrics: existingMetrics || {
234
- totalConversationCount: 0,
235
- },
236
- };
237
- }
238
-
239
- function projectParticipantContextField(world = {}) {
240
- const requiredFields = Array.isArray(world.joinSchema?.requiredFields) ? world.joinSchema.requiredFields : [];
241
- const field = requiredFields[0] || buildDefaultEntryProfileField();
242
- return {
243
- fieldId: field.fieldId,
244
- label: field.label,
245
- description: field.description || null,
246
- };
247
- }
248
-
249
- function projectWorldStats(store, world = {}, conversationFeedbackService = null) {
250
- const totalParticipants = store.countMemberships({ worldId: world.worldId });
251
- const activeParticipants = store.countMemberships({ worldId: world.worldId, status: 'active' });
252
- const feedbackSummary = conversationFeedbackService?.summarizeWorld?.({ worldId: world.worldId }) || {
253
- totalLikes: 0,
254
- totalDislikes: 0,
255
- };
256
- return {
257
- totalParticipants,
258
- activeParticipants,
259
- totalConversationCount: Number(world.metrics?.totalConversationCount || 0),
260
- totalLikes: feedbackSummary.totalLikes,
261
- totalDislikes: feedbackSummary.totalDislikes,
262
- };
263
- }
264
-
265
- function projectManagedWorldSummary(store, world = {}, { worldRole = null, conversationFeedbackService = null } = {}) {
266
- return {
267
- worldId: world.worldId,
268
- displayName: world.displayName,
269
- worldContextText: world.worldContextText || '',
270
- ownerAgentId: world.creatorAgentId || null,
271
- enabled: world.enabled === true,
272
- status: world.status || 'draft',
273
- worldRole: normalizeWorldRole(worldRole, null),
274
- createdAt: world.createdAt || null,
275
- updatedAt: world.updatedAt || null,
276
- stats: projectWorldStats(store, world, conversationFeedbackService),
277
- };
278
- }
279
-
280
- function projectManagedWorld(store, world = {}, { worldRole = null, conversationFeedbackService = null } = {}) {
281
- return {
282
- worldId: world.worldId,
283
- displayName: world.displayName,
284
- worldContextText: world.worldContextText || '',
285
- ownerAgentId: world.creatorAgentId || null,
286
- enabled: world.enabled === true,
287
- status: world.status || 'draft',
288
- worldRole: normalizeWorldRole(worldRole, null),
289
- schemaVersion: Number(world.schemaVersion || 1),
290
- createdAt: world.createdAt || null,
291
- updatedAt: world.updatedAt || null,
292
- participantContextField: projectParticipantContextField(world),
293
- stats: projectWorldStats(store, world, conversationFeedbackService),
294
- };
295
- }
296
-
297
- function buildWorldId(displayName, existingIds = []) {
298
- const base = `ugc-${slugify(displayName, 'world')}`;
299
- if (!existingIds.includes(base)) return base;
300
-
301
- let counter = 2;
302
- while (existingIds.includes(`${base}-${counter}`)) {
303
- counter += 1;
304
- }
305
- return `${base}-${counter}`;
306
- }
307
-
308
- export function createWorldAdminService({
309
- worldService,
310
- worldAuthorizationService,
311
- store = null,
312
- publicIdentityService = null,
313
- conversationFeedbackService = null,
314
- } = {}) {
315
- function assertStore() {
316
- if (!store) throw createConfigurationError();
317
- return store;
318
- }
319
-
320
- function assertActorAgent(agentId) {
321
- const actorAgentId = normalizeAgentId(agentId);
322
- if (!actorAgentId) throw createInvalidWorldRequestError('agentId', 'agentId is required');
323
- const agent = assertStore().getAgent(actorAgentId);
324
- if (!agent) throw createAgentNotFoundError(actorAgentId);
325
- return actorAgentId;
326
- }
327
-
328
- function requireWorldOwner({ worldId, actorAgentId } = {}) {
329
- const authorization = worldAuthorizationService.evaluateWorldAction({
330
- worldId,
331
- actorAgentId,
332
- action: WORLD_ACTIONS.MANAGE_WORLD,
333
- includeDisabled: true,
334
- });
335
- if (!authorization.allowed) {
336
- throw createWorldActionNotAllowedError({
337
- worldId: authorization.world.worldId,
338
- agentId: actorAgentId,
339
- action: WORLD_ACTIONS.MANAGE_WORLD,
340
- actorRole: authorization.worldRole,
341
- allowedRoles: authorization.allowedRoles,
342
- });
343
- }
344
- return authorization;
345
- }
346
-
347
- function hasManageWorldChanges(changes = null) {
348
- if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return false;
349
- return Object.keys(changes).length > 0;
350
- }
351
-
352
- return {
353
- async createWorld({
354
- ownerAgentId,
355
- creatorAgentId,
356
- displayName,
357
- worldContextText,
358
- enabled = true,
359
- status = null,
360
- } = {}) {
361
- const storeBacked = assertStore();
362
- const resolvedOwnerAgentId = assertActorAgent(ownerAgentId || creatorAgentId);
363
- publicIdentityService?.assertPublicIdentityReady?.({
364
- agentId: resolvedOwnerAgentId,
365
- capability: 'create world',
366
- });
367
- const resolvedDisplayName = normalizeText(displayName, null);
368
- if (!resolvedDisplayName) throw createInvalidWorldRequestError('displayName');
369
- const resolvedWorldContextText = normalizeText(worldContextText, null);
370
- if (!resolvedWorldContextText) throw createInvalidWorldRequestError('worldContextText');
371
-
372
- const worldId = buildWorldId(resolvedDisplayName, worldService.listWorldIds());
373
- const worldRecord = buildWorldRecord({
374
- worldId,
375
- creatorAgentId: resolvedOwnerAgentId,
376
- displayName: resolvedDisplayName,
377
- summary: summarizeWorldContextText(resolvedWorldContextText, resolvedDisplayName),
378
- worldContextText: resolvedWorldContextText,
379
- enabled: normalizeBoolean(enabled, true),
380
- status: normalizeOwnerWorldStatus(status, normalizeBoolean(enabled, true) ? 'enabled' : 'draft'),
381
- });
382
-
383
- const created = await storeBacked.createWorldConfig(worldRecord);
384
- const normalizedWorld = worldService.requireWorld(created.worldId, { includeDisabled: true });
385
-
386
- return projectManagedWorld(storeBacked, normalizedWorld, {
387
- worldRole: WORLD_ROLES.OWNER,
388
- conversationFeedbackService,
389
- });
390
- },
391
- listManagedWorlds({ actorAgentId, creatorAgentId, includeDisabled = true } = {}) {
392
- const storeBacked = assertStore();
393
- const resolvedActorAgentId = assertActorAgent(actorAgentId || creatorAgentId);
394
- return worldService
395
- .listOwnedWorlds({ creatorAgentId: resolvedActorAgentId, includeDisabled })
396
- .map((world) => worldAuthorizationService.resolveWorldActorContext({
397
- worldId: world.worldId,
398
- actorAgentId: resolvedActorAgentId,
399
- includeDisabled,
400
- }))
401
- .map((context) => projectManagedWorldSummary(storeBacked, context.world, {
402
- worldRole: context.worldRole,
403
- conversationFeedbackService,
404
- }));
405
- },
406
- listOwnedWorlds(input = {}) {
407
- return this.listManagedWorlds(input);
408
- },
409
- getManagedWorld({ actorAgentId, creatorAgentId, worldId } = {}) {
410
- const storeBacked = assertStore();
411
- const resolvedActorAgentId = assertActorAgent(actorAgentId || creatorAgentId);
412
- const authorization = requireWorldOwner({
413
- worldId,
414
- actorAgentId: resolvedActorAgentId,
415
- });
416
- return projectManagedWorld(storeBacked, authorization.world, {
417
- worldRole: authorization.worldRole,
418
- conversationFeedbackService,
419
- });
420
- },
421
- async manageWorld({ actorAgentId, creatorAgentId, worldId, changes = null, enabled = null, status = null } = {}) {
422
- const storeBacked = assertStore();
423
- const resolvedActorAgentId = assertActorAgent(actorAgentId || creatorAgentId);
424
- const hasChanges = changes && typeof changes === 'object' && !Array.isArray(changes);
425
- const normalizedStatus = normalizeOwnerWorldStatus(status, null);
426
- const resolvedEnabled = normalizedStatus != null
427
- ? inferEnabledFromOwnerWorldStatus(normalizedStatus, null)
428
- : (enabled == null ? null : normalizeBoolean(enabled, false));
429
-
430
- const authorization = requireWorldOwner({
431
- worldId,
432
- actorAgentId: resolvedActorAgentId,
433
- });
434
-
435
- const existingWorld = authorization.world;
436
- if (!hasChanges && resolvedEnabled == null && normalizedStatus == null) {
437
- return projectManagedWorld(storeBacked, existingWorld, {
438
- worldRole: authorization.worldRole,
439
- conversationFeedbackService,
440
- });
441
- }
442
-
443
- let nextRecord = existingWorld;
444
-
445
- if (hasChanges) {
446
- const nextDisplayName = normalizeText(changes.displayName, existingWorld.displayName);
447
- const nextWorldContextText = Object.prototype.hasOwnProperty.call(changes, 'worldContextText')
448
- ? normalizeText(changes.worldContextText, null)
449
- : existingWorld.worldContextText;
450
- nextRecord = buildWorldRecord({
451
- worldId: existingWorld.worldId,
452
- creatorAgentId: existingWorld.creatorAgentId,
453
- displayName: nextDisplayName,
454
- summary: summarizeWorldContextText(nextWorldContextText, nextDisplayName),
455
- worldContextText: nextWorldContextText,
456
- enabled: resolvedEnabled == null ? existingWorld.enabled === true : resolvedEnabled,
457
- status: normalizedStatus || (
458
- resolvedEnabled == null
459
- ? existingWorld.status
460
- : (resolvedEnabled ? 'enabled' : 'disabled')
461
- ),
462
- existingMetrics: existingWorld.metrics || null,
463
- });
464
- } else if (resolvedEnabled != null || normalizedStatus != null) {
465
- const nextEnabled = resolvedEnabled == null ? existingWorld.enabled === true : resolvedEnabled;
466
- const nextStatus = normalizedStatus || (nextEnabled ? 'enabled' : 'disabled');
467
- nextRecord = {
468
- ...existingWorld,
469
- enabled: nextEnabled,
470
- status: nextStatus,
471
- meta: {
472
- ...(existingWorld.meta || {}),
473
- status: projectOwnerWorldMetaStatus(nextStatus, nextEnabled),
474
- },
475
- };
476
- }
477
-
478
- const updated = await storeBacked.updateWorldConfig(existingWorld.worldId, nextRecord);
479
- const normalizedWorld = worldService.requireWorld(updated.worldId, { includeDisabled: true });
480
- return projectManagedWorld(storeBacked, normalizedWorld, {
481
- worldRole: authorization.worldRole,
482
- conversationFeedbackService,
483
- });
484
- },
485
- };
486
- }