@xfxstudio/claworld 0.1.0

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 (69) hide show
  1. package/README.md +60 -0
  2. package/bin/claworld.mjs +9 -0
  3. package/index.js +51 -0
  4. package/openclaw.plugin.json +470 -0
  5. package/package.json +76 -0
  6. package/setup-entry.js +6 -0
  7. package/src/lib/accepted-chat-kickoff.js +192 -0
  8. package/src/lib/agent-address.js +46 -0
  9. package/src/lib/agent-profile.js +69 -0
  10. package/src/lib/http-auth.js +151 -0
  11. package/src/lib/policy.js +118 -0
  12. package/src/lib/runtime-errors.js +149 -0
  13. package/src/lib/runtime-guidance.js +458 -0
  14. package/src/openclaw/index.js +53 -0
  15. package/src/openclaw/installer/cli.js +349 -0
  16. package/src/openclaw/installer/constants.js +6 -0
  17. package/src/openclaw/installer/core.js +1548 -0
  18. package/src/openclaw/installer/doctor.js +690 -0
  19. package/src/openclaw/installer/workspace-contract.js +403 -0
  20. package/src/openclaw/plugin/account-identity.js +66 -0
  21. package/src/openclaw/plugin/claworld-channel-plugin.js +3118 -0
  22. package/src/openclaw/plugin/config-schema.js +464 -0
  23. package/src/openclaw/plugin/lifecycle.js +114 -0
  24. package/src/openclaw/plugin/managed-config.js +648 -0
  25. package/src/openclaw/plugin/onboarding.js +291 -0
  26. package/src/openclaw/plugin/register.js +961 -0
  27. package/src/openclaw/plugin/relay-client.js +783 -0
  28. package/src/openclaw/plugin/runtime.js +12 -0
  29. package/src/openclaw/protocol/relay-event-protocol.js +31 -0
  30. package/src/openclaw/runtime/canonical-result-builder.js +116 -0
  31. package/src/openclaw/runtime/demo-session-bootstrap.js +37 -0
  32. package/src/openclaw/runtime/feedback-helper.js +145 -0
  33. package/src/openclaw/runtime/inbound-session-router.js +36 -0
  34. package/src/openclaw/runtime/outbound-session-bridge.js +17 -0
  35. package/src/openclaw/runtime/product-shell-helper.js +1712 -0
  36. package/src/openclaw/runtime/runtime-path.js +19 -0
  37. package/src/openclaw/runtime/system-message-orchestrator.js +1 -0
  38. package/src/openclaw/runtime/tool-contracts.js +714 -0
  39. package/src/openclaw/runtime/tool-inventory.js +92 -0
  40. package/src/openclaw/runtime/world-moderation-helper.js +415 -0
  41. package/src/openclaw/runtime/world-session-startup.js +1 -0
  42. package/src/product-shell/catalog/default-world-catalog.js +296 -0
  43. package/src/product-shell/contracts/candidate-feed.js +330 -0
  44. package/src/product-shell/contracts/chat-request-approval-policy.js +98 -0
  45. package/src/product-shell/contracts/world-manifest.js +435 -0
  46. package/src/product-shell/contracts/world-orchestration.js +1024 -0
  47. package/src/product-shell/feedback/feedback-contract.js +13 -0
  48. package/src/product-shell/feedback/feedback-routes.js +98 -0
  49. package/src/product-shell/feedback/feedback-service.js +254 -0
  50. package/src/product-shell/index.js +163 -0
  51. package/src/product-shell/matching/matchmaking-service.js +340 -0
  52. package/src/product-shell/membership/membership-service.js +277 -0
  53. package/src/product-shell/onboarding/onboarding-routes.js +37 -0
  54. package/src/product-shell/onboarding/onboarding-service.js +230 -0
  55. package/src/product-shell/orchestration/session-orchestrator.js +38 -0
  56. package/src/product-shell/results/result-service.js +15 -0
  57. package/src/product-shell/search/search-service.js +359 -0
  58. package/src/product-shell/social/chat-request-approval-policy.js +332 -0
  59. package/src/product-shell/social/chat-request-routes.js +108 -0
  60. package/src/product-shell/social/chat-request-service.js +632 -0
  61. package/src/product-shell/social/friend-routes.js +82 -0
  62. package/src/product-shell/social/friend-service.js +560 -0
  63. package/src/product-shell/social/social-routes.js +21 -0
  64. package/src/product-shell/social/social-service.js +140 -0
  65. package/src/product-shell/worlds/world-admin-service.js +705 -0
  66. package/src/product-shell/worlds/world-authorization.js +135 -0
  67. package/src/product-shell/worlds/world-broadcast-service.js +299 -0
  68. package/src/product-shell/worlds/world-routes.js +410 -0
  69. package/src/product-shell/worlds/world-service.js +89 -0
@@ -0,0 +1,714 @@
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 normalizeInteger(value, fallback = 0) {
8
+ const parsed = Number(value);
9
+ if (!Number.isFinite(parsed)) return fallback;
10
+ return Math.max(0, Math.trunc(parsed));
11
+ }
12
+
13
+ function normalizePositiveInteger(value, fallback = null) {
14
+ const parsed = Number(value);
15
+ if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
16
+ return Math.max(1, Math.trunc(parsed));
17
+ }
18
+
19
+ function normalizeOptionalBoolean(value, fallback = null) {
20
+ if (typeof value === 'boolean') return value;
21
+ return fallback;
22
+ }
23
+
24
+ function normalizeOptionalInteger(value, fallback = null) {
25
+ const parsed = Number(value);
26
+ if (!Number.isFinite(parsed)) return fallback;
27
+ return Math.trunc(parsed);
28
+ }
29
+
30
+ function normalizeStringList(values = []) {
31
+ if (!Array.isArray(values)) return [];
32
+ return values
33
+ .map((value) => normalizeText(value, null))
34
+ .filter(Boolean);
35
+ }
36
+
37
+ function summarizeProfileSnippet(profileSummary = {}) {
38
+ const headline = normalizeText(profileSummary.headline, null);
39
+ if (headline) return headline;
40
+
41
+ const required = Array.isArray(profileSummary.requiredFields) ? profileSummary.requiredFields : [];
42
+ const optional = Array.isArray(profileSummary.optionalFields) ? profileSummary.optionalFields : [];
43
+ const allFields = [...required, ...optional]
44
+ .map((field) => {
45
+ const label = normalizeText(field.label, field.fieldId || 'Field');
46
+ const value = Array.isArray(field.value) ? field.value.join(', ') : normalizeText(field.value, null);
47
+ if (!value) return null;
48
+ return `${label}: ${value}`;
49
+ })
50
+ .filter(Boolean);
51
+
52
+ return allFields[0] || null;
53
+ }
54
+
55
+ function projectEntryProfileFields(worldDetail = {}) {
56
+ const requiredFields = Array.isArray(worldDetail.requiredFields) ? worldDetail.requiredFields : [];
57
+ const optionalFields = Array.isArray(worldDetail.optionalFields) ? worldDetail.optionalFields : [];
58
+ const searchableFieldIds = new Set(
59
+ Array.isArray(worldDetail.searchSchema?.inputFieldIds) ? worldDetail.searchSchema.inputFieldIds : [],
60
+ );
61
+
62
+ return [...requiredFields, ...optionalFields].map((field) => ({
63
+ fieldId: field.fieldId,
64
+ label: field.label,
65
+ required: field.required === true,
66
+ searchable: searchableFieldIds.has(field.fieldId),
67
+ description: field.description || null,
68
+ examples: normalizeStringList(field.examples),
69
+ }));
70
+ }
71
+
72
+ function projectProfileField(field = {}) {
73
+ return {
74
+ fieldId: normalizeText(field.fieldId, null),
75
+ label: normalizeText(field.label, normalizeText(field.fieldId, 'Field')),
76
+ required: field.required === true,
77
+ description: normalizeText(field.description, null),
78
+ examples: normalizeStringList(field.examples),
79
+ constraints: field.constraints && typeof field.constraints === 'object' ? field.constraints : null,
80
+ };
81
+ }
82
+
83
+ function projectSearchMatchReasons(item = {}) {
84
+ if (Array.isArray(item.matchedFields) && item.matchedFields.length > 0) {
85
+ return item.matchedFields.map((field) => {
86
+ if (field.matchType === 'overlap' && Array.isArray(field.sharedValues) && field.sharedValues.length > 0) {
87
+ return `${field.label}: ${field.sharedValues.join(', ')}`;
88
+ }
89
+ return `${field.label} matches`;
90
+ });
91
+ }
92
+
93
+ return [normalizeText(item.reasonSummary, 'Recently active online world member.')];
94
+ }
95
+
96
+ function projectModerationEntryProfileSchema(schema = null) {
97
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return null;
98
+ return {
99
+ fields: Array.isArray(schema.fields)
100
+ ? schema.fields.map((field) => ({
101
+ fieldId: field.fieldId,
102
+ label: field.label,
103
+ type: field.type,
104
+ required: typeof field.required === 'boolean' ? field.required : null,
105
+ searchable: typeof field.searchable === 'boolean' ? field.searchable : null,
106
+ description: field.description || null,
107
+ examples: normalizeStringList(field.examples),
108
+ }))
109
+ : [],
110
+ };
111
+ }
112
+
113
+ function projectModerationSessionTemplate(sessionTemplate = null) {
114
+ if (!sessionTemplate || typeof sessionTemplate !== 'object' || Array.isArray(sessionTemplate)) return null;
115
+
116
+ return {
117
+ mode: normalizeText(sessionTemplate.mode, null),
118
+ maxTurns: normalizePositiveInteger(sessionTemplate.maxTurns, null),
119
+ turnTimeoutMs: normalizePositiveInteger(sessionTemplate.turnTimeoutMs, null),
120
+ raiseHandPolicy: sessionTemplate.raiseHandPolicy && typeof sessionTemplate.raiseHandPolicy === 'object'
121
+ ? {
122
+ mode: normalizeText(sessionTemplate.raiseHandPolicy.mode, null),
123
+ summary: normalizeText(sessionTemplate.raiseHandPolicy.summary, null),
124
+ }
125
+ : null,
126
+ };
127
+ }
128
+
129
+ function projectModerationBroadcastConfig(broadcast = null) {
130
+ if (!broadcast || typeof broadcast !== 'object' || Array.isArray(broadcast)) return null;
131
+
132
+ return {
133
+ enabled: normalizeOptionalBoolean(broadcast.enabled, null),
134
+ audience: normalizeText(broadcast.audience, null),
135
+ replyPolicy: normalizeText(broadcast.replyPolicy, null),
136
+ excludeSelf: typeof broadcast.excludeSelf === 'boolean' ? broadcast.excludeSelf : null,
137
+ };
138
+ }
139
+
140
+ function projectWorldRole(worldRole, fallback = null) {
141
+ const normalized = normalizeText(worldRole, fallback);
142
+ return ['owner', 'admin', 'member'].includes(normalized) ? normalized : fallback;
143
+ }
144
+
145
+ function projectWorldStats(stats = null) {
146
+ if (!stats || typeof stats !== 'object' || Array.isArray(stats)) return null;
147
+ return {
148
+ totalParticipants: normalizeOptionalInteger(stats.totalParticipants, null),
149
+ activeParticipants: normalizeOptionalInteger(stats.activeParticipants, null),
150
+ totalConversationCount: normalizeOptionalInteger(stats.totalConversationCount, null),
151
+ };
152
+ }
153
+
154
+ function projectOrchestration(orchestration = null) {
155
+ if (!orchestration || typeof orchestration !== 'object' || Array.isArray(orchestration)) return null;
156
+ return {
157
+ stage: normalizeText(orchestration.stage, null),
158
+ system: normalizeText(orchestration.system, null),
159
+ confirmation: normalizeText(orchestration.confirmation, null),
160
+ user: normalizeText(orchestration.user, null),
161
+ followUp: normalizeText(orchestration.followUp, null),
162
+ };
163
+ }
164
+
165
+ export function projectToolWorldList(worldDirectory = {}) {
166
+ const worlds = Array.isArray(worldDirectory.items)
167
+ ? [...worldDirectory.items]
168
+ .map((world) => ({
169
+ worldId: world.worldId,
170
+ displayName: world.displayName,
171
+ summary: world.summary,
172
+ hotness: normalizeInteger(world.hotness, 0),
173
+ }))
174
+ .sort((left, right) => right.hotness - left.hotness || left.displayName.localeCompare(right.displayName))
175
+ : [];
176
+
177
+ return {
178
+ worlds,
179
+ pagination: worldDirectory.pagination && typeof worldDirectory.pagination === 'object'
180
+ ? {
181
+ page: normalizeInteger(worldDirectory.pagination.page, 1),
182
+ totalPages: normalizeInteger(worldDirectory.pagination.totalPages, 0),
183
+ totalCount: normalizeInteger(worldDirectory.pagination.totalCount, worlds.length),
184
+ }
185
+ : {
186
+ page: 1,
187
+ totalPages: worlds.length > 0 ? 1 : 0,
188
+ totalCount: worlds.length,
189
+ },
190
+ };
191
+ }
192
+
193
+ export function projectToolWorldDetail(worldDetail = {}) {
194
+ return {
195
+ worldId: worldDetail.worldId,
196
+ displayName: worldDetail.displayName,
197
+ description: normalizeText(worldDetail.description, worldDetail.summary || ''),
198
+ entryProfileSchema: {
199
+ fields: projectEntryProfileFields(worldDetail),
200
+ },
201
+ interactionRules: normalizeText(worldDetail.interactionRules, ''),
202
+ prohibitedRules: normalizeText(worldDetail.prohibitedRules, ''),
203
+ ratingRules: normalizeText(worldDetail.ratingRules, ''),
204
+ adminAgentIds: Array.isArray(worldDetail.adminAgentIds) ? worldDetail.adminAgentIds : [],
205
+ eligibility: normalizeText(worldDetail.eligibility, null),
206
+ broadcast: projectModerationBroadcastConfig(worldDetail.broadcast),
207
+ };
208
+ }
209
+
210
+ export function projectToolWorldProfileCollectionResponse(
211
+ flow = {},
212
+ {
213
+ accountId = null,
214
+ continueToolName = null,
215
+ joinToolName = null,
216
+ } = {},
217
+ ) {
218
+ const profileDraft = flow.profile && typeof flow.profile === 'object' ? flow.profile : {};
219
+ const missingRequiredFields = Array.isArray(flow.joinCheck?.missingFields)
220
+ ? flow.joinCheck.missingFields.map((field) => projectProfileField(field))
221
+ : [];
222
+ const promptFields = Array.isArray(flow.promptFields)
223
+ ? flow.promptFields.map((field) => projectProfileField(field))
224
+ : [];
225
+ const nextMissingField = flow.joinCheck?.nextMissingField
226
+ ? projectProfileField(flow.joinCheck.nextMissingField)
227
+ : (promptFields[0] || null);
228
+ const normalizedAccountId = normalizeText(accountId, null);
229
+ const normalizedWorldId = normalizeText(flow.worldId, null);
230
+ const readyToJoin = flow.accepted === true;
231
+
232
+ return {
233
+ status: readyToJoin ? 'ready_to_join' : 'needs_profile',
234
+ worldId: normalizedWorldId,
235
+ accountId: normalizedAccountId,
236
+ profileDraft,
237
+ providedRequiredFieldIds: normalizeStringList(flow.providedRequiredFieldIds),
238
+ missingRequiredFields,
239
+ nextMissingField,
240
+ promptFields,
241
+ remainingRequiredFieldCount: normalizeInteger(
242
+ flow.remainingRequiredFieldCount,
243
+ missingRequiredFields.length,
244
+ ),
245
+ revalidationCheckpoint: flow.revalidationCheckpoint && typeof flow.revalidationCheckpoint === 'object'
246
+ ? {
247
+ mode: normalizeText(
248
+ flow.revalidationCheckpoint.mode,
249
+ readyToJoin ? 'complete' : 'after_each_reply',
250
+ ),
251
+ promptFieldIds: normalizeStringList(flow.revalidationCheckpoint.promptFieldIds),
252
+ }
253
+ : {
254
+ mode: readyToJoin ? 'complete' : 'after_each_reply',
255
+ promptFieldIds: promptFields.map((field) => field.fieldId).filter(Boolean),
256
+ },
257
+ nextAction: readyToJoin
258
+ ? 'retry_join_with_profile_draft'
259
+ : 'collect_missing_profile_fields_and_recheck',
260
+ nextTool: readyToJoin ? normalizeText(joinToolName, null) : normalizeText(continueToolName, null),
261
+ continueTool: normalizeText(continueToolName, null),
262
+ joinTool: normalizeText(joinToolName, null),
263
+ joinPayload: readyToJoin && normalizedWorldId
264
+ ? {
265
+ accountId: normalizedAccountId,
266
+ worldId: normalizedWorldId,
267
+ profileSnapshot: profileDraft,
268
+ }
269
+ : null,
270
+ orchestration: projectOrchestration(flow.orchestration),
271
+ guidance: flow.orchestration && typeof flow.orchestration === 'object'
272
+ ? {
273
+ user: normalizeText(flow.orchestration.user, null),
274
+ followUp: normalizeText(flow.orchestration.followUp, null),
275
+ }
276
+ : null,
277
+ };
278
+ }
279
+
280
+ export function projectToolJoinWorldResponse(
281
+ joinResult = {},
282
+ {
283
+ accountId = null,
284
+ continueToolName = 'claworld_prepare_world_join',
285
+ joinToolName = 'claworld_join_world',
286
+ } = {},
287
+ ) {
288
+ if (joinResult.status === 'needs_profile') {
289
+ if (joinResult.profileCollectionFlow && typeof joinResult.profileCollectionFlow === 'object') {
290
+ return {
291
+ ...projectToolWorldProfileCollectionResponse(joinResult.profileCollectionFlow, {
292
+ accountId,
293
+ continueToolName,
294
+ joinToolName,
295
+ }),
296
+ membershipStatus: joinResult.membershipStatus || 'inactive',
297
+ searchEnabled: false,
298
+ nextAction: 'collect_missing_profile_fields_and_retry_join',
299
+ };
300
+ }
301
+
302
+ const profileDraft = joinResult.normalizedProfile && typeof joinResult.normalizedProfile === 'object'
303
+ ? joinResult.normalizedProfile
304
+ : {};
305
+ return {
306
+ status: 'needs_profile',
307
+ worldId: joinResult.worldId,
308
+ accountId: normalizeText(accountId, null),
309
+ membershipStatus: joinResult.membershipStatus || 'inactive',
310
+ searchEnabled: false,
311
+ missingRequiredFields: Array.isArray(joinResult.missingRequiredFields) ? joinResult.missingRequiredFields : [],
312
+ nextMissingField: joinResult.nextMissingField || null,
313
+ profileDraft,
314
+ nextAction: 'collect_missing_profile_fields_and_retry_join',
315
+ nextTool: normalizeText(continueToolName, null),
316
+ continueTool: normalizeText(continueToolName, null),
317
+ joinTool: normalizeText(joinToolName, null),
318
+ orchestration: projectOrchestration(joinResult.orchestration),
319
+ guidance: joinResult.orchestration && typeof joinResult.orchestration === 'object'
320
+ ? {
321
+ user: normalizeText(joinResult.orchestration.user, null),
322
+ followUp: normalizeText(joinResult.orchestration.followUp, null),
323
+ }
324
+ : null,
325
+ };
326
+ }
327
+
328
+ return {
329
+ status: joinResult.status === 'activated' ? 'activated' : 'accepted',
330
+ worldId: joinResult.worldId,
331
+ accountId: normalizeText(accountId, null),
332
+ membershipStatus: joinResult.membershipStatus || 'unknown',
333
+ searchEnabled: joinResult.searchEnabled === true,
334
+ orchestration: projectOrchestration(joinResult.orchestration),
335
+ guidance: joinResult.orchestration && typeof joinResult.orchestration === 'object'
336
+ ? {
337
+ user: normalizeText(joinResult.orchestration.user, null),
338
+ followUp: normalizeText(joinResult.orchestration.followUp, null),
339
+ }
340
+ : null,
341
+ };
342
+ }
343
+
344
+ export function projectToolSearchWorldResponse(searchResult = {}, { accountId = null } = {}) {
345
+ if (searchResult.status === 'not_joined') {
346
+ return {
347
+ status: 'not_joined',
348
+ worldId: searchResult.worldId,
349
+ accountId: normalizeText(accountId, null),
350
+ query: searchResult.query || {},
351
+ limit: normalizeInteger(searchResult.limit, 10),
352
+ results: [],
353
+ message: normalizeText(searchResult.message, 'Join the world before searching it.'),
354
+ };
355
+ }
356
+
357
+ const results = Array.isArray(searchResult.results)
358
+ ? searchResult.results.map((item) => ({
359
+ agentId: normalizeText(item.agentId, normalizeText(item.playerId, null)),
360
+ playerId: normalizeText(item.playerId, normalizeText(item.agentId, null)),
361
+ displayName: item.displayName,
362
+ headline: item.headline || null,
363
+ score: normalizeInteger(item.score, 0),
364
+ matchReasons: projectSearchMatchReasons(item),
365
+ profileSnippet: summarizeProfileSnippet(item.profileSummary),
366
+ online: item.online === true,
367
+ }))
368
+ : [];
369
+
370
+ return {
371
+ status: results.length > 0 ? 'ready' : 'empty',
372
+ worldId: searchResult.worldId,
373
+ accountId: normalizeText(accountId, null),
374
+ query: searchResult.query || {},
375
+ limit: normalizeInteger(searchResult.limit, results.length || 10),
376
+ results,
377
+ };
378
+ }
379
+
380
+ export function projectToolCreateWorldResponse(world = {}, { accountId = null } = {}) {
381
+ return {
382
+ worldId: world.worldId,
383
+ accountId: normalizeText(accountId, null),
384
+ status: normalizeText(world.status, null),
385
+ enabled: normalizeOptionalBoolean(world.enabled, null),
386
+ worldRole: projectWorldRole(world.worldRole, null),
387
+ schemaVersion: normalizeOptionalInteger(world.schemaVersion, null),
388
+ createdAt: normalizeText(world.createdAt, null),
389
+ adminAgentIds: Array.isArray(world.adminAgentIds) ? world.adminAgentIds : [],
390
+ eligibility: normalizeText(world.eligibility, null),
391
+ broadcast: projectModerationBroadcastConfig(world.broadcast),
392
+ sessionTemplate: projectModerationSessionTemplate(world.sessionTemplate),
393
+ };
394
+ }
395
+
396
+ export function projectToolOwnedWorldsResponse(payload = {}, { accountId = null } = {}) {
397
+ const worlds = Array.isArray(payload.items)
398
+ ? payload.items.map((world) => ({
399
+ worldId: world.worldId,
400
+ displayName: world.displayName,
401
+ summary: world.summary,
402
+ enabled: normalizeOptionalBoolean(world.enabled, null),
403
+ status: normalizeText(world.status, null),
404
+ worldRole: projectWorldRole(world.worldRole, null),
405
+ createdAt: normalizeText(world.createdAt, null),
406
+ updatedAt: normalizeText(world.updatedAt, null),
407
+ stats: projectWorldStats(world.stats),
408
+ }))
409
+ : [];
410
+
411
+ return {
412
+ accountId: normalizeText(accountId, null),
413
+ worlds,
414
+ };
415
+ }
416
+
417
+ export function projectToolManagedWorldResponse(world = {}, { accountId = null } = {}) {
418
+ return {
419
+ worldId: world.worldId,
420
+ accountId: normalizeText(accountId, null),
421
+ displayName: world.displayName,
422
+ summary: world.summary,
423
+ description: world.description,
424
+ enabled: normalizeOptionalBoolean(world.enabled, null),
425
+ status: normalizeText(world.status, null),
426
+ worldRole: projectWorldRole(world.worldRole, null),
427
+ schemaVersion: normalizeOptionalInteger(world.schemaVersion, null),
428
+ createdAt: normalizeText(world.createdAt, null),
429
+ updatedAt: normalizeText(world.updatedAt, null),
430
+ adminAgentIds: Array.isArray(world.adminAgentIds) ? world.adminAgentIds : [],
431
+ eligibility: normalizeText(world.eligibility, null),
432
+ broadcast: projectModerationBroadcastConfig(world.broadcast),
433
+ entryProfileSchema: projectModerationEntryProfileSchema(world.entryProfileSchema),
434
+ interactionRules: normalizeText(world.interactionRules, null),
435
+ prohibitedRules: normalizeText(world.prohibitedRules, null),
436
+ ratingRules: normalizeText(world.ratingRules, null),
437
+ sessionTemplate: projectModerationSessionTemplate(world.sessionTemplate),
438
+ stats: projectWorldStats(world.stats),
439
+ };
440
+ }
441
+
442
+ export function projectToolBroadcastWorldResponse(result = {}, { accountId = null } = {}) {
443
+ const requests = Array.isArray(result.requests)
444
+ ? result.requests.map((request) => ({
445
+ agentId: normalizeText(
446
+ request.agentId,
447
+ request.chatRequest?.toAgent?.agentId || request.chatRequest?.counterparty?.agentId || null,
448
+ ),
449
+ status: normalizeText(request.status, 'created'),
450
+ chatRequest: projectChatRequestItem(request.chatRequest),
451
+ }))
452
+ : [];
453
+ const failures = Array.isArray(result.failures)
454
+ ? result.failures.map((failure) => ({
455
+ agentId: normalizeText(failure.agentId, null),
456
+ status: normalizeText(failure.status, 'failed'),
457
+ httpStatus: normalizeInteger(failure.httpStatus, 0),
458
+ error: normalizeText(failure.error, null),
459
+ reason: normalizeText(failure.reason, null),
460
+ message: normalizeText(failure.message, null),
461
+ }))
462
+ : [];
463
+
464
+ return {
465
+ status: normalizeText(result.status, null),
466
+ accountId: normalizeText(accountId, null),
467
+ worldId: normalizeText(result.worldId, null),
468
+ senderAgentId: normalizeText(result.senderAgentId, null),
469
+ senderRole: normalizeText(result.senderRole, null),
470
+ audience: normalizeText(result.audience, null),
471
+ excludeSelf: normalizeOptionalBoolean(result.excludeSelf, null),
472
+ eligibility: normalizeText(result.eligibility, null),
473
+ broadcastId: normalizeText(result.broadcastId, null),
474
+ totalTargets: normalizeInteger(result.totalTargets, requests.length + failures.length),
475
+ createdCount: normalizeInteger(result.createdCount, requests.length),
476
+ failedCount: normalizeInteger(result.failedCount, failures.length),
477
+ nextAction: normalizeText(result.nextAction, null),
478
+ requests,
479
+ failures,
480
+ };
481
+ }
482
+
483
+ export function projectToolFeedbackSubmissionResponse(result = {}) {
484
+ const feedback = result.feedback && typeof result.feedback === 'object' ? result.feedback : {};
485
+ const reporter = feedback.reporter && typeof feedback.reporter === 'object' ? feedback.reporter : {};
486
+ const context = feedback.context && typeof feedback.context === 'object' ? feedback.context : {};
487
+ const runtimeContext = feedback.runtimeContext && typeof feedback.runtimeContext === 'object'
488
+ ? feedback.runtimeContext
489
+ : {};
490
+
491
+ return {
492
+ status: normalizeText(result.status, 'recorded'),
493
+ feedbackId: normalizeText(feedback.feedbackId, null),
494
+ category: normalizeText(feedback.category, null),
495
+ impact: normalizeText(feedback.impact, 'medium'),
496
+ title: normalizeText(feedback.title, null),
497
+ accountId: normalizeText(feedback.accountId, null),
498
+ reporterAgentId: normalizeText(reporter.agentId, null),
499
+ reporterAgentCode: normalizeText(reporter.agentCode, null),
500
+ worldId: normalizeText(context.worldId, null),
501
+ sessionId: normalizeText(context.sessionId, null),
502
+ tags: normalizeStringList(context.tags),
503
+ createdAt: normalizeText(feedback.createdAt, null),
504
+ runtime: {
505
+ channelId: normalizeText(runtimeContext.channelId, null),
506
+ toolName: normalizeText(runtimeContext.toolName, null),
507
+ toolCallId: normalizeText(runtimeContext.toolCallId, null),
508
+ pluginVersion: normalizeText(runtimeContext.pluginVersion, null),
509
+ },
510
+ nextAction: 'keep_feedback_id_for_follow_up',
511
+ };
512
+ }
513
+
514
+ function projectToolAgentSummary(agent = {}) {
515
+ if (!agent || typeof agent !== 'object') return null;
516
+ return {
517
+ agentId: normalizeText(agent.agentId, null),
518
+ agentCode: normalizeText(agent.agentCode, null),
519
+ address: normalizeText(agent.address, null),
520
+ displayName: normalizeText(agent.displayName, null),
521
+ online: agent.online === true,
522
+ discoverable: typeof agent.discoverable === 'boolean' ? agent.discoverable : null,
523
+ contactable: typeof agent.contactable === 'boolean' ? agent.contactable : null,
524
+ };
525
+ }
526
+
527
+ function projectFriendshipSummary(friendship = {}) {
528
+ if (!friendship || typeof friendship !== 'object') return null;
529
+ return {
530
+ friendshipId: normalizeText(friendship.friendshipId, null),
531
+ status: normalizeText(friendship.status, null),
532
+ peerAgentId: normalizeText(friendship.peerAgentId, null),
533
+ peerAgent: projectToolAgentSummary(friendship.peerAgent),
534
+ acceptedAt: normalizeText(friendship.acceptedAt, null),
535
+ updatedAt: normalizeText(friendship.updatedAt, null),
536
+ };
537
+ }
538
+
539
+ function projectToolWorldSummary(world = {}) {
540
+ if (!world || typeof world !== 'object') return null;
541
+ return {
542
+ worldId: normalizeText(world.worldId, null),
543
+ slug: normalizeText(world.slug, null),
544
+ displayName: normalizeText(world.displayName, null),
545
+ summary: normalizeText(world.summary, null),
546
+ };
547
+ }
548
+
549
+ function normalizeConversationScopeDetails(input = {}) {
550
+ const conversation = input && typeof input === 'object' && !Array.isArray(input) ? input : {};
551
+ const worldId = normalizeText(conversation.worldId, null);
552
+ const maxTurns = normalizePositiveInteger(conversation.maxTurns, null);
553
+ const turnTimeoutMs = normalizePositiveInteger(conversation.turnTimeoutMs, null);
554
+ const raiseHandPolicy = conversation.raiseHandPolicy && typeof conversation.raiseHandPolicy === 'object' && !Array.isArray(conversation.raiseHandPolicy)
555
+ ? {
556
+ mode: normalizeText(conversation.raiseHandPolicy.mode, null),
557
+ summary: normalizeText(conversation.raiseHandPolicy.summary, null),
558
+ }
559
+ : null;
560
+ const episodePolicy = maxTurns != null || turnTimeoutMs != null || raiseHandPolicy
561
+ ? {
562
+ ...(maxTurns != null ? { maxTurns } : {}),
563
+ ...(turnTimeoutMs != null ? { turnTimeoutMs } : {}),
564
+ ...(raiseHandPolicy ? { raiseHandPolicy } : {}),
565
+ }
566
+ : null;
567
+ return {
568
+ mode: worldId ? 'world' : 'direct',
569
+ worldId,
570
+ world: projectToolWorldSummary(conversation.world),
571
+ ...(episodePolicy ? { episodePolicy } : {}),
572
+ };
573
+ }
574
+
575
+ function projectFriendRequestItem(request = {}) {
576
+ if (!request || typeof request !== 'object') return null;
577
+ return {
578
+ friendRequestId: normalizeText(request.friendRequestId, null),
579
+ status: normalizeText(request.status, 'pending'),
580
+ direction: normalizeText(request.direction, null),
581
+ message: normalizeText(request.message, null),
582
+ createdAt: normalizeText(request.createdAt, null),
583
+ respondedAt: normalizeText(request.respondedAt, null),
584
+ fromAgent: projectToolAgentSummary(request.fromAgent),
585
+ toAgent: projectToolAgentSummary(request.toAgent),
586
+ };
587
+ }
588
+
589
+ function projectChatRequestKickoff(kickoff = {}) {
590
+ if (!kickoff || typeof kickoff !== 'object') return null;
591
+ return {
592
+ status: normalizeText(kickoff.status, 'skipped'),
593
+ deliveredAt: normalizeText(kickoff.deliveredAt, null),
594
+ reason: normalizeText(kickoff.reason, null),
595
+ };
596
+ }
597
+
598
+ function projectChatRequestOrigin(origin = {}) {
599
+ if (!origin || typeof origin !== 'object' || Array.isArray(origin)) return null;
600
+ return {
601
+ type: normalizeText(origin.type, 'chat_request'),
602
+ broadcastId: normalizeText(origin.broadcastId, null),
603
+ };
604
+ }
605
+
606
+ function projectChatRequestItem(request = {}) {
607
+ if (!request || typeof request !== 'object') return null;
608
+ const requestContext = request.requestContext && typeof request.requestContext === 'object' && !Array.isArray(request.requestContext)
609
+ ? request.requestContext
610
+ : {};
611
+ const kickoffBrief = request.kickoffBrief && typeof request.kickoffBrief === 'object' && !Array.isArray(request.kickoffBrief)
612
+ ? request.kickoffBrief
613
+ : requestContext.kickoffBrief && typeof requestContext.kickoffBrief === 'object' && !Array.isArray(requestContext.kickoffBrief)
614
+ ? requestContext.kickoffBrief
615
+ : null;
616
+ const conversation = normalizeConversationScopeDetails(
617
+ request.conversation && typeof request.conversation === 'object' && !Array.isArray(request.conversation)
618
+ ? request.conversation
619
+ : requestContext.conversation,
620
+ );
621
+ return {
622
+ chatRequestId: normalizeText(request.chatRequestId || request.requestId, null),
623
+ status: normalizeText(request.status, 'pending'),
624
+ direction: normalizeText(request.direction, null),
625
+ openingMessage: normalizeText(
626
+ request.openingMessage,
627
+ normalizeText(kickoffBrief?.text, normalizeText(requestContext.openingPayload?.text, normalizeText(requestContext.message, null))),
628
+ ),
629
+ kickoffBrief: kickoffBrief
630
+ ? {
631
+ text: normalizeText(kickoffBrief.text, null),
632
+ payload: kickoffBrief.payload && typeof kickoffBrief.payload === 'object' && !Array.isArray(kickoffBrief.payload)
633
+ ? kickoffBrief.payload
634
+ : null,
635
+ source: normalizeText(kickoffBrief.source, 'chat_request_brief'),
636
+ }
637
+ : null,
638
+ createdAt: normalizeText(request.createdAt, null),
639
+ respondedAt: normalizeText(request.respondedAt, null),
640
+ expiresAt: normalizeText(request.expiresAt, null),
641
+ origin: projectChatRequestOrigin(request.origin),
642
+ fromAgent: projectToolAgentSummary(request.fromAgent),
643
+ toAgent: projectToolAgentSummary(request.toAgent),
644
+ counterparty: projectToolAgentSummary(request.counterparty),
645
+ conversation,
646
+ };
647
+ }
648
+
649
+ export function projectToolFriendRequestMutationResponse(result = {}, { accountId = null } = {}) {
650
+ return {
651
+ status: result.alreadyFriends === true
652
+ ? 'already_friends'
653
+ : normalizeText(result.request?.status, 'pending'),
654
+ accountId: normalizeText(accountId, null),
655
+ created: result.created === true,
656
+ alreadyFriends: result.alreadyFriends === true,
657
+ request: projectFriendRequestItem(result.request),
658
+ friendship: projectFriendshipSummary(result.friendship),
659
+ nextAction: result.alreadyFriends === true
660
+ ? 'friendship_active'
661
+ : normalizeText(result.request?.status, 'pending') === 'pending'
662
+ ? 'wait_for_peer_friend_request_decision'
663
+ : 'friendship_active',
664
+ };
665
+ }
666
+
667
+ export function projectToolFriendRequestListResponse(result = {}, { accountId = null } = {}) {
668
+ const items = Array.isArray(result.items)
669
+ ? result.items.map((request) => projectFriendRequestItem(request)).filter(Boolean)
670
+ : [];
671
+ return {
672
+ accountId: normalizeText(accountId, null),
673
+ items,
674
+ };
675
+ }
676
+
677
+ export function projectToolChatRequestMutationResponse(result = {}, { accountId = null } = {}) {
678
+ const request = result.chatRequest && typeof result.chatRequest === 'object'
679
+ ? result.chatRequest
680
+ : result.request && typeof result.request === 'object'
681
+ ? result.request
682
+ : result;
683
+ const projectedRequest = projectChatRequestItem(request);
684
+ const kickoff = projectChatRequestKickoff(result.kickoff || result.request?.kickoff);
685
+ const normalizedStatus = normalizeText(result.status, projectedRequest?.status || 'pending');
686
+ return {
687
+ status: normalizedStatus,
688
+ accountId: normalizeText(accountId, null),
689
+ chatRequest: projectedRequest,
690
+ kickoff,
691
+ nextAction: normalizeText(
692
+ result.nextAction,
693
+ normalizedStatus === 'accepted'
694
+ ? kickoff?.status === 'sent'
695
+ ? 'runtime_owns_live_conversation'
696
+ : kickoff?.status === 'failed'
697
+ ? 'backend_kickoff_failed'
698
+ : 'chat_request_accepted_without_opening_message'
699
+ : normalizedStatus === 'pending'
700
+ ? 'wait_for_peer_acceptance'
701
+ : 'chat_request_closed',
702
+ ),
703
+ };
704
+ }
705
+
706
+ export function projectToolChatRequestListResponse(result = {}, { accountId = null } = {}) {
707
+ const items = Array.isArray(result.items)
708
+ ? result.items.map((request) => projectChatRequestItem(request)).filter(Boolean)
709
+ : [];
710
+ return {
711
+ accountId: normalizeText(accountId, null),
712
+ items,
713
+ };
714
+ }