@xfxstudio/claworld 0.1.4 → 0.2.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.
- package/README.md +12 -29
- package/openclaw.plugin.json +9 -33
- package/package.json +2 -10
- package/skills/claworld-help/SKILL.md +86 -160
- package/skills/claworld-join-and-chat/SKILL.md +107 -203
- package/skills/claworld-manage-worlds/SKILL.md +75 -392
- package/src/lib/chat-request.js +347 -0
- package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
- package/src/openclaw/index.js +0 -5
- package/src/openclaw/installer/cli.js +14 -16
- package/src/openclaw/installer/core.js +13 -14
- package/src/openclaw/installer/doctor.js +69 -31
- package/src/openclaw/installer/workspace-contract.js +33 -9
- package/src/openclaw/plugin/claworld-channel-plugin.js +156 -625
- package/src/openclaw/plugin/config-schema.js +4 -16
- package/src/openclaw/plugin/managed-config.js +127 -75
- package/src/openclaw/plugin/onboarding.js +7 -3
- package/src/openclaw/plugin/register.js +40 -339
- package/src/openclaw/plugin/relay-client.js +112 -102
- package/src/openclaw/protocol/relay-event-protocol.js +34 -22
- package/src/openclaw/runtime/canonical-result-builder.js +15 -5
- package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
- package/src/openclaw/runtime/feedback-helper.js +3 -2
- package/src/openclaw/runtime/inbound-session-router.js +28 -20
- package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
- package/src/openclaw/runtime/product-shell-helper.js +45 -637
- package/src/openclaw/runtime/runtime-path.js +2 -2
- package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
- package/src/openclaw/runtime/tool-contracts.js +36 -258
- package/src/openclaw/runtime/world-moderation-helper.js +11 -65
- package/src/product-shell/catalog/default-world-catalog.js +15 -33
- package/src/product-shell/contracts/candidate-feed.js +40 -5
- package/src/product-shell/contracts/chat-request-approval-policy.js +3 -3
- package/src/product-shell/contracts/world-manifest.js +134 -161
- package/src/product-shell/contracts/world-orchestration.js +55 -326
- package/src/product-shell/feedback/feedback-routes.js +4 -3
- package/src/product-shell/feedback/feedback-service.js +11 -8
- package/src/product-shell/index.js +6 -7
- package/src/product-shell/matching/matchmaking-service.js +39 -5
- package/src/product-shell/membership/membership-service.js +125 -147
- package/src/product-shell/onboarding/onboarding-service.js +2 -2
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
- package/src/product-shell/orchestration/world-conversation-text.js +231 -0
- package/src/product-shell/results/result-service.js +9 -3
- package/src/product-shell/search/search-service.js +28 -1
- package/src/product-shell/social/chat-request-routes.js +0 -1
- package/src/product-shell/social/chat-request-service.js +1 -102
- package/src/product-shell/worlds/world-admin-service.js +86 -277
- package/src/product-shell/worlds/world-authorization.js +3 -5
- package/src/product-shell/worlds/world-routes.js +8 -38
- package/src/product-shell/worlds/world-service.js +3 -3
- package/src/product-shell/worlds/world-text.js +77 -0
- package/src/lib/runtime-guidance.js +0 -457
- package/src/openclaw/runtime/world-session-startup.js +0 -1
- package/src/product-shell/orchestration/session-orchestrator.js +0 -38
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WORLD_ACTIONS, WORLD_ROLES } from './world-authorization.js';
|
|
2
|
+
import { buildWorldContextText } from './world-text.js';
|
|
2
3
|
|
|
3
4
|
function normalizeText(value, fallback = null) {
|
|
4
5
|
if (value == null) return fallback;
|
|
@@ -41,6 +42,16 @@ function normalizeBroadcastReplyPolicy(value, fallback = 'zero') {
|
|
|
41
42
|
return 'zero';
|
|
42
43
|
}
|
|
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
|
+
|
|
44
55
|
function slugify(value, fallback = 'world') {
|
|
45
56
|
const normalized = normalizeText(value, fallback)
|
|
46
57
|
.toLowerCase()
|
|
@@ -117,175 +128,49 @@ function normalizeWorldRole(worldRole, fallback = null) {
|
|
|
117
128
|
return [WORLD_ROLES.OWNER, WORLD_ROLES.ADMIN, WORLD_ROLES.MEMBER].includes(normalized) ? normalized : fallback;
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
function
|
|
121
|
-
const normalized = normalizeText(type, 'string');
|
|
122
|
-
if (['string', 'string[]', 'number', 'boolean'].includes(normalized)) return normalized;
|
|
123
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields.type', `unsupported field type: ${normalized}`);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function normalizeEntryProfileField(field = {}, index = 0) {
|
|
127
|
-
const label = normalizeText(field.label, null);
|
|
128
|
-
const fieldId = normalizeText(field.fieldId, label ? slugify(label, `field-${index + 1}`) : `field_${index + 1}`);
|
|
129
|
-
if (!fieldId) {
|
|
130
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields.fieldId');
|
|
131
|
-
}
|
|
132
|
-
|
|
131
|
+
function buildDefaultEntryProfileField() {
|
|
133
132
|
return {
|
|
134
|
-
fieldId,
|
|
135
|
-
label:
|
|
136
|
-
type:
|
|
137
|
-
required:
|
|
138
|
-
searchable:
|
|
139
|
-
description:
|
|
140
|
-
examples:
|
|
133
|
+
fieldId: 'participantContextText',
|
|
134
|
+
label: 'Entry Profile',
|
|
135
|
+
type: 'string',
|
|
136
|
+
required: true,
|
|
137
|
+
searchable: true,
|
|
138
|
+
description: 'Free-form participant profile/context text used for world join, search, and candidate review.',
|
|
139
|
+
examples: [],
|
|
141
140
|
};
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
function
|
|
145
|
-
const rawFields = Array.isArray(input?.fields) ? input.fields : (Array.isArray(input) ? input : []);
|
|
146
|
-
if (rawFields.length === 0) {
|
|
147
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields', 'at least one profile field is required');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const fields = rawFields.map((field, index) => normalizeEntryProfileField(field, index));
|
|
151
|
-
const fieldIds = new Set();
|
|
152
|
-
for (const field of fields) {
|
|
153
|
-
if (fieldIds.has(field.fieldId)) {
|
|
154
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields.fieldId', `duplicate fieldId: ${field.fieldId}`);
|
|
155
|
-
}
|
|
156
|
-
fieldIds.add(field.fieldId);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const requiredFields = fields.filter((field) => field.required);
|
|
160
|
-
if (requiredFields.length === 0) {
|
|
161
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields.required', 'at least one required profile field is required');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const searchableFields = fields.filter((field) => field.searchable);
|
|
165
|
-
if (searchableFields.length === 0) {
|
|
166
|
-
throw createInvalidWorldRequestError('entryProfileSchema.fields.searchable', 'at least one searchable field is required');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
fields,
|
|
171
|
-
requiredFields,
|
|
172
|
-
optionalFields: fields.filter((field) => !field.required),
|
|
173
|
-
searchableFieldIds: searchableFields.map((field) => field.fieldId),
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function normalizeAdminAgentIds(adminAgentIds, { creatorAgentId = null, store = null } = {}) {
|
|
178
|
-
if (adminAgentIds == null) return [];
|
|
179
|
-
if (!Array.isArray(adminAgentIds)) {
|
|
180
|
-
throw createInvalidWorldRequestError('adminAgentIds', 'adminAgentIds must be an array of agent ids');
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const normalizedCreatorAgentId = normalizeAgentId(creatorAgentId);
|
|
184
|
-
const uniqueAgentIds = [];
|
|
185
|
-
const seen = new Set();
|
|
186
|
-
|
|
187
|
-
for (const rawAgentId of adminAgentIds) {
|
|
188
|
-
const agentId = normalizeAgentId(rawAgentId);
|
|
189
|
-
if (!agentId || seen.has(agentId) || agentId === normalizedCreatorAgentId) continue;
|
|
190
|
-
if (store && !store.getAgent(agentId)) {
|
|
191
|
-
throw createInvalidWorldRequestError('adminAgentIds', `unknown admin agent: ${agentId}`);
|
|
192
|
-
}
|
|
193
|
-
seen.add(agentId);
|
|
194
|
-
uniqueAgentIds.push(agentId);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return uniqueAgentIds;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function normalizeBroadcastConfig(broadcast, { existingBroadcast = null } = {}) {
|
|
201
|
-
if (broadcast !== undefined && (broadcast == null || typeof broadcast !== 'object' || Array.isArray(broadcast))) {
|
|
202
|
-
throw createInvalidWorldRequestError('broadcast', 'broadcast must be an object');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const source = broadcast === undefined ? existingBroadcast : broadcast;
|
|
206
|
-
const normalized = source && typeof source === 'object' && !Array.isArray(source)
|
|
207
|
-
? source
|
|
208
|
-
: {};
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
enabled: normalized.enabled === true,
|
|
212
|
-
audience: normalizeBroadcastAudience(
|
|
213
|
-
normalized.audience,
|
|
214
|
-
normalizeBroadcastAudience(existingBroadcast?.audience, 'members'),
|
|
215
|
-
),
|
|
216
|
-
replyPolicy: normalizeBroadcastReplyPolicy(
|
|
217
|
-
normalized.replyPolicy,
|
|
218
|
-
normalizeBroadcastReplyPolicy(existingBroadcast?.replyPolicy, 'zero'),
|
|
219
|
-
),
|
|
220
|
-
excludeSelf: normalized.excludeSelf === undefined
|
|
221
|
-
? existingBroadcast?.excludeSelf !== false
|
|
222
|
-
: normalized.excludeSelf !== false,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function buildSearchSchema(entryProfileSchema) {
|
|
143
|
+
function buildSearchSchema() {
|
|
227
144
|
return {
|
|
228
145
|
mode: 'profile_overlap_search',
|
|
229
|
-
inputFieldIds:
|
|
146
|
+
inputFieldIds: ['participantContextText'],
|
|
230
147
|
summary:
|
|
231
|
-
'
|
|
148
|
+
'Manual world search over active online members using participantContextText. Candidate feed review is the canonical path before request_chat.',
|
|
232
149
|
onlineOnly: true,
|
|
233
150
|
defaultLimit: 10,
|
|
234
151
|
};
|
|
235
152
|
}
|
|
236
153
|
|
|
237
|
-
function buildMatchingStrategy(
|
|
154
|
+
function buildMatchingStrategy() {
|
|
238
155
|
return {
|
|
239
156
|
mode: 'profile_overlap',
|
|
240
157
|
cadence: 'on_demand',
|
|
241
158
|
strategySummary:
|
|
242
|
-
|
|
243
|
-
candidateSources: ['
|
|
159
|
+
'Rank active online world members by overlap on participantContextText, deliver candidate summaries first, and let members request_chat after review.',
|
|
160
|
+
candidateSources: ['active_memberships_online'],
|
|
244
161
|
};
|
|
245
162
|
}
|
|
246
163
|
|
|
247
|
-
function
|
|
248
|
-
const sessionTemplateProvided = sessionTemplate !== undefined;
|
|
249
|
-
if (sessionTemplateProvided) {
|
|
250
|
-
if (!sessionTemplate || typeof sessionTemplate !== 'object' || Array.isArray(sessionTemplate)) {
|
|
251
|
-
throw createInvalidWorldRequestError(
|
|
252
|
-
'sessionTemplate.maxTurns',
|
|
253
|
-
'sessionTemplate.maxTurns is required',
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const explicitMaxTurns = normalizePositiveInteger(sessionTemplate.maxTurns, null);
|
|
258
|
-
if (explicitMaxTurns == null) {
|
|
259
|
-
throw createInvalidWorldRequestError(
|
|
260
|
-
'sessionTemplate.maxTurns',
|
|
261
|
-
'sessionTemplate.maxTurns must be a positive integer',
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
return explicitMaxTurns;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const existingMaxTurns = normalizePositiveInteger(existingSessionTemplate?.maxTurns, null);
|
|
268
|
-
if (existingMaxTurns != null) return existingMaxTurns;
|
|
269
|
-
if (required) throw createInvalidWorldRequestError('sessionTemplate.maxTurns');
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function buildSessionTemplate(interactionRules, prohibitedRules, { maxTurns, existingSessionTemplate = null } = {}) {
|
|
164
|
+
function buildConversationTemplate(interactionRules, prohibitedRules, { existingConversationTemplate = null } = {}) {
|
|
274
165
|
return {
|
|
275
|
-
mode: normalizeText(
|
|
276
|
-
maxTurns,
|
|
277
|
-
turnTimeoutMs: normalizePositiveInteger(existingSessionTemplate?.turnTimeoutMs, 60_000),
|
|
278
|
-
raiseHandPolicy: {
|
|
279
|
-
mode: normalizeText(existingSessionTemplate?.raiseHandPolicy?.mode, 'dual_raise_hand'),
|
|
280
|
-
summary: prohibitedRules || 'Both agents should stop once neither side has useful new questions.',
|
|
281
|
-
},
|
|
166
|
+
mode: normalizeText(existingConversationTemplate?.mode, 'a2a'),
|
|
282
167
|
worldRules: {
|
|
283
168
|
openingText: interactionRules,
|
|
284
|
-
turnMessageRules: Array.isArray(
|
|
285
|
-
?
|
|
169
|
+
turnMessageRules: Array.isArray(existingConversationTemplate?.worldRules?.turnMessageRules)
|
|
170
|
+
? existingConversationTemplate.worldRules.turnMessageRules
|
|
286
171
|
: [],
|
|
287
|
-
convergence:
|
|
288
|
-
stateChangeMessages:
|
|
172
|
+
convergence: existingConversationTemplate?.worldRules?.convergence || {},
|
|
173
|
+
stateChangeMessages: existingConversationTemplate?.worldRules?.stateChangeMessages || {},
|
|
289
174
|
},
|
|
290
175
|
};
|
|
291
176
|
}
|
|
@@ -306,31 +191,20 @@ function buildResultContract(worldId, ratingRules) {
|
|
|
306
191
|
function buildWorldRecord({
|
|
307
192
|
worldId,
|
|
308
193
|
creatorAgentId,
|
|
309
|
-
adminAgentIds = [],
|
|
310
|
-
eligibility = 'active',
|
|
311
|
-
broadcast = undefined,
|
|
312
194
|
displayName,
|
|
313
195
|
summary,
|
|
314
196
|
description,
|
|
315
197
|
interactionRules,
|
|
316
198
|
prohibitedRules,
|
|
317
199
|
ratingRules,
|
|
318
|
-
|
|
200
|
+
worldContextText = null,
|
|
319
201
|
enabled = false,
|
|
320
202
|
status = null,
|
|
321
203
|
schemaVersion = 1,
|
|
322
204
|
existingMetrics = null,
|
|
323
|
-
sessionTemplate = undefined,
|
|
324
|
-
existingSessionTemplate = null,
|
|
325
|
-
existingBroadcast = null,
|
|
326
205
|
} = {}) {
|
|
327
206
|
const resolvedStatus = status || (enabled ? 'enabled' : 'draft');
|
|
328
|
-
const
|
|
329
|
-
existingSessionTemplate,
|
|
330
|
-
required: existingSessionTemplate == null,
|
|
331
|
-
});
|
|
332
|
-
const resolvedEligibility = normalizeWorldEligibility(eligibility, 'active');
|
|
333
|
-
const resolvedBroadcast = normalizeBroadcastConfig(broadcast, { existingBroadcast });
|
|
207
|
+
const participantContextField = buildDefaultEntryProfileField();
|
|
334
208
|
|
|
335
209
|
return {
|
|
336
210
|
worldId,
|
|
@@ -344,17 +218,25 @@ function buildWorldRecord({
|
|
|
344
218
|
interactionRules,
|
|
345
219
|
prohibitedRules,
|
|
346
220
|
ratingRules,
|
|
221
|
+
worldContextText: buildWorldContextText({
|
|
222
|
+
worldId,
|
|
223
|
+
displayName,
|
|
224
|
+
summary,
|
|
225
|
+
worldContextText,
|
|
226
|
+
interactionRules,
|
|
227
|
+
prohibitedRules,
|
|
228
|
+
ratingRules,
|
|
229
|
+
}),
|
|
347
230
|
roles: [],
|
|
348
231
|
joinSchema: {
|
|
349
|
-
requiredFields:
|
|
350
|
-
optionalFields:
|
|
232
|
+
requiredFields: [participantContextField],
|
|
233
|
+
optionalFields: [],
|
|
351
234
|
hints: [],
|
|
352
235
|
},
|
|
353
|
-
searchSchema: buildSearchSchema(
|
|
354
|
-
matching: buildMatchingStrategy(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
existingSessionTemplate,
|
|
236
|
+
searchSchema: buildSearchSchema(),
|
|
237
|
+
matching: buildMatchingStrategy(),
|
|
238
|
+
conversationTemplate: buildConversationTemplate(interactionRules, prohibitedRules, {
|
|
239
|
+
existingConversationTemplate,
|
|
358
240
|
}),
|
|
359
241
|
resultContract: buildResultContract(worldId, ratingRules),
|
|
360
242
|
meta: {
|
|
@@ -362,9 +244,14 @@ function buildWorldRecord({
|
|
|
362
244
|
persistence: 'store',
|
|
363
245
|
},
|
|
364
246
|
creatorAgentId,
|
|
365
|
-
adminAgentIds,
|
|
366
|
-
eligibility:
|
|
367
|
-
broadcast:
|
|
247
|
+
adminAgentIds: [],
|
|
248
|
+
eligibility: 'active',
|
|
249
|
+
broadcast: {
|
|
250
|
+
enabled: false,
|
|
251
|
+
audience: 'members',
|
|
252
|
+
replyPolicy: 'zero',
|
|
253
|
+
excludeSelf: true,
|
|
254
|
+
},
|
|
368
255
|
status: resolvedStatus,
|
|
369
256
|
enabled,
|
|
370
257
|
schemaVersion,
|
|
@@ -374,21 +261,13 @@ function buildWorldRecord({
|
|
|
374
261
|
};
|
|
375
262
|
}
|
|
376
263
|
|
|
377
|
-
function
|
|
264
|
+
function projectParticipantContextField(world = {}) {
|
|
378
265
|
const requiredFields = Array.isArray(world.joinSchema?.requiredFields) ? world.joinSchema.requiredFields : [];
|
|
379
|
-
const
|
|
380
|
-
const searchableFieldIds = new Set(Array.isArray(world.searchSchema?.inputFieldIds) ? world.searchSchema.inputFieldIds : []);
|
|
381
|
-
|
|
266
|
+
const field = requiredFields[0] || buildDefaultEntryProfileField();
|
|
382
267
|
return {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
type: field.type,
|
|
387
|
-
required: field.required === true,
|
|
388
|
-
searchable: searchableFieldIds.has(field.fieldId),
|
|
389
|
-
description: field.description || null,
|
|
390
|
-
examples: normalizeStringList(field.examples),
|
|
391
|
-
})),
|
|
268
|
+
fieldId: field.fieldId,
|
|
269
|
+
label: field.label,
|
|
270
|
+
description: field.description || null,
|
|
392
271
|
};
|
|
393
272
|
}
|
|
394
273
|
|
|
@@ -406,7 +285,8 @@ function projectManagedWorldSummary(store, world = {}, { worldRole = null } = {}
|
|
|
406
285
|
return {
|
|
407
286
|
worldId: world.worldId,
|
|
408
287
|
displayName: world.displayName,
|
|
409
|
-
|
|
288
|
+
worldContextText: world.worldContextText || '',
|
|
289
|
+
ownerAgentId: world.creatorAgentId || null,
|
|
410
290
|
enabled: world.enabled === true,
|
|
411
291
|
status: world.status || 'draft',
|
|
412
292
|
worldRole: normalizeWorldRole(worldRole, null),
|
|
@@ -420,24 +300,15 @@ function projectManagedWorld(store, world = {}, { worldRole = null } = {}) {
|
|
|
420
300
|
return {
|
|
421
301
|
worldId: world.worldId,
|
|
422
302
|
displayName: world.displayName,
|
|
423
|
-
|
|
424
|
-
|
|
303
|
+
worldContextText: world.worldContextText || '',
|
|
304
|
+
ownerAgentId: world.creatorAgentId || null,
|
|
425
305
|
enabled: world.enabled === true,
|
|
426
306
|
status: world.status || 'draft',
|
|
427
307
|
worldRole: normalizeWorldRole(worldRole, null),
|
|
428
308
|
schemaVersion: Number(world.schemaVersion || 1),
|
|
429
309
|
createdAt: world.createdAt || null,
|
|
430
310
|
updatedAt: world.updatedAt || null,
|
|
431
|
-
|
|
432
|
-
eligibility: normalizeWorldEligibility(world.eligibility, 'active'),
|
|
433
|
-
broadcast: normalizeBroadcastConfig(world.broadcast, {
|
|
434
|
-
existingBroadcast: world.broadcast || null,
|
|
435
|
-
}),
|
|
436
|
-
entryProfileSchema: projectEntryProfileSchema(world),
|
|
437
|
-
interactionRules: world.interactionRules || '',
|
|
438
|
-
prohibitedRules: world.prohibitedRules || '',
|
|
439
|
-
ratingRules: world.ratingRules || '',
|
|
440
|
-
sessionTemplate: world.sessionTemplate || null,
|
|
311
|
+
participantContextField: projectParticipantContextField(world),
|
|
441
312
|
stats: projectWorldStats(store, world),
|
|
442
313
|
};
|
|
443
314
|
}
|
|
@@ -499,60 +370,35 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
499
370
|
|
|
500
371
|
function hasManageWorldChanges(changes = null) {
|
|
501
372
|
if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return false;
|
|
502
|
-
return Object.keys(changes).
|
|
373
|
+
return Object.keys(changes).length > 0;
|
|
503
374
|
}
|
|
504
375
|
|
|
505
376
|
return {
|
|
506
377
|
async createWorld({
|
|
507
378
|
ownerAgentId,
|
|
508
379
|
creatorAgentId,
|
|
509
|
-
adminAgentIds = [],
|
|
510
|
-
eligibility = 'active',
|
|
511
|
-
broadcast = undefined,
|
|
512
380
|
displayName,
|
|
513
|
-
|
|
514
|
-
description,
|
|
515
|
-
entryProfileSchema,
|
|
516
|
-
interactionRules,
|
|
517
|
-
prohibitedRules,
|
|
518
|
-
ratingRules,
|
|
519
|
-
sessionTemplate,
|
|
381
|
+
worldContextText,
|
|
520
382
|
enabled = false,
|
|
521
383
|
} = {}) {
|
|
522
384
|
const storeBacked = assertStore();
|
|
523
385
|
const resolvedOwnerAgentId = assertActorAgent(ownerAgentId || creatorAgentId);
|
|
524
386
|
const resolvedDisplayName = normalizeText(displayName, null);
|
|
525
387
|
if (!resolvedDisplayName) throw createInvalidWorldRequestError('displayName');
|
|
526
|
-
const
|
|
527
|
-
if (!
|
|
528
|
-
|
|
529
|
-
const resolvedInteractionRules = normalizeText(interactionRules, null);
|
|
530
|
-
if (!resolvedInteractionRules) throw createInvalidWorldRequestError('interactionRules');
|
|
531
|
-
const resolvedProhibitedRules = normalizeText(prohibitedRules, null);
|
|
532
|
-
if (!resolvedProhibitedRules) throw createInvalidWorldRequestError('prohibitedRules');
|
|
533
|
-
const resolvedRatingRules = normalizeText(ratingRules, null);
|
|
534
|
-
if (!resolvedRatingRules) throw createInvalidWorldRequestError('ratingRules');
|
|
535
|
-
|
|
536
|
-
const normalizedEntryProfileSchema = normalizeEntryProfileSchema(entryProfileSchema);
|
|
537
|
-
const normalizedAdminAgentIds = normalizeAdminAgentIds(adminAgentIds, {
|
|
538
|
-
creatorAgentId: resolvedOwnerAgentId,
|
|
539
|
-
store: storeBacked,
|
|
540
|
-
});
|
|
388
|
+
const resolvedWorldContextText = normalizeText(worldContextText, null);
|
|
389
|
+
if (!resolvedWorldContextText) throw createInvalidWorldRequestError('worldContextText');
|
|
390
|
+
|
|
541
391
|
const worldId = buildWorldId(resolvedDisplayName, worldService.listWorldIds());
|
|
542
392
|
const worldRecord = buildWorldRecord({
|
|
543
393
|
worldId,
|
|
544
394
|
creatorAgentId: resolvedOwnerAgentId,
|
|
545
|
-
adminAgentIds: normalizedAdminAgentIds,
|
|
546
|
-
eligibility,
|
|
547
|
-
broadcast,
|
|
548
395
|
displayName: resolvedDisplayName,
|
|
549
|
-
summary:
|
|
550
|
-
description:
|
|
551
|
-
interactionRules:
|
|
552
|
-
prohibitedRules:
|
|
553
|
-
ratingRules:
|
|
554
|
-
|
|
555
|
-
sessionTemplate,
|
|
396
|
+
summary: summarizeWorldContextText(resolvedWorldContextText, resolvedDisplayName),
|
|
397
|
+
description: resolvedWorldContextText,
|
|
398
|
+
interactionRules: null,
|
|
399
|
+
prohibitedRules: null,
|
|
400
|
+
ratingRules: null,
|
|
401
|
+
worldContextText: resolvedWorldContextText,
|
|
556
402
|
enabled: normalizeBoolean(enabled, false),
|
|
557
403
|
});
|
|
558
404
|
|
|
@@ -604,13 +450,6 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
604
450
|
action: WORLD_ACTIONS.MANAGE_WORLD,
|
|
605
451
|
});
|
|
606
452
|
}
|
|
607
|
-
if (hasChanges && Object.prototype.hasOwnProperty.call(changes, 'adminAgentIds')) {
|
|
608
|
-
authorization = requireWorldAction({
|
|
609
|
-
worldId,
|
|
610
|
-
actorAgentId: resolvedActorAgentId,
|
|
611
|
-
action: WORLD_ACTIONS.MANAGE_WORLD_ROLES,
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
453
|
if (enabled != null) {
|
|
615
454
|
authorization = requireWorldAction({
|
|
616
455
|
worldId,
|
|
@@ -631,49 +470,19 @@ export function createWorldAdminService({ worldService, worldAuthorizationServic
|
|
|
631
470
|
|
|
632
471
|
if (hasChanges) {
|
|
633
472
|
const nextDisplayName = normalizeText(changes.displayName, existingWorld.displayName);
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const nextProhibitedRules = normalizeText(changes.prohibitedRules, existingWorld.prohibitedRules);
|
|
638
|
-
const nextRatingRules = normalizeText(changes.ratingRules, existingWorld.ratingRules);
|
|
639
|
-
const nextSessionTemplate = Object.prototype.hasOwnProperty.call(changes, 'sessionTemplate')
|
|
640
|
-
? changes.sessionTemplate
|
|
641
|
-
: undefined;
|
|
642
|
-
const nextAdminAgentIds = Object.prototype.hasOwnProperty.call(changes, 'adminAgentIds')
|
|
643
|
-
? normalizeAdminAgentIds(changes.adminAgentIds, {
|
|
644
|
-
creatorAgentId: existingWorld.creatorAgentId,
|
|
645
|
-
store: storeBacked,
|
|
646
|
-
})
|
|
647
|
-
: (Array.isArray(existingWorld.adminAgentIds) ? existingWorld.adminAgentIds : []);
|
|
648
|
-
const nextEligibility = Object.prototype.hasOwnProperty.call(changes, 'eligibility')
|
|
649
|
-
? normalizeWorldEligibility(changes.eligibility, existingWorld.eligibility || 'active')
|
|
650
|
-
: normalizeWorldEligibility(existingWorld.eligibility, 'active');
|
|
651
|
-
const nextBroadcast = Object.prototype.hasOwnProperty.call(changes, 'broadcast')
|
|
652
|
-
? changes.broadcast
|
|
653
|
-
: undefined;
|
|
654
|
-
let entryProfileSchema = null;
|
|
655
|
-
|
|
656
|
-
if (Object.prototype.hasOwnProperty.call(changes, 'entryProfileSchema')) {
|
|
657
|
-
entryProfileSchema = normalizeEntryProfileSchema(changes.entryProfileSchema);
|
|
658
|
-
nextSchemaVersion += 1;
|
|
659
|
-
}
|
|
660
|
-
|
|
473
|
+
const nextWorldContextText = Object.prototype.hasOwnProperty.call(changes, 'worldContextText')
|
|
474
|
+
? normalizeText(changes.worldContextText, null)
|
|
475
|
+
: existingWorld.worldContextText;
|
|
661
476
|
nextRecord = buildWorldRecord({
|
|
662
477
|
worldId: existingWorld.worldId,
|
|
663
478
|
creatorAgentId: existingWorld.creatorAgentId,
|
|
664
|
-
adminAgentIds: nextAdminAgentIds,
|
|
665
|
-
eligibility: nextEligibility,
|
|
666
|
-
broadcast: nextBroadcast,
|
|
667
479
|
displayName: nextDisplayName,
|
|
668
|
-
summary:
|
|
669
|
-
description:
|
|
670
|
-
interactionRules:
|
|
671
|
-
prohibitedRules:
|
|
672
|
-
ratingRules:
|
|
673
|
-
|
|
674
|
-
sessionTemplate: nextSessionTemplate,
|
|
675
|
-
existingSessionTemplate: existingWorld.sessionTemplate || null,
|
|
676
|
-
existingBroadcast: existingWorld.broadcast || null,
|
|
480
|
+
summary: summarizeWorldContextText(nextWorldContextText, nextDisplayName),
|
|
481
|
+
description: nextWorldContextText,
|
|
482
|
+
interactionRules: null,
|
|
483
|
+
prohibitedRules: null,
|
|
484
|
+
ratingRules: null,
|
|
485
|
+
worldContextText: nextWorldContextText,
|
|
677
486
|
enabled: enabled == null ? existingWorld.enabled === true : normalizeBoolean(enabled, false),
|
|
678
487
|
status: enabled == null
|
|
679
488
|
? existingWorld.status
|
|
@@ -6,7 +6,6 @@ function normalizeText(value, fallback = null) {
|
|
|
6
6
|
|
|
7
7
|
export const WORLD_ROLES = Object.freeze({
|
|
8
8
|
OWNER: 'owner',
|
|
9
|
-
ADMIN: 'admin',
|
|
10
9
|
MEMBER: 'member',
|
|
11
10
|
NONE: 'none',
|
|
12
11
|
});
|
|
@@ -24,7 +23,6 @@ export const WORLD_ACTIONS = Object.freeze({
|
|
|
24
23
|
|
|
25
24
|
function resolveWorldRole({ isOwner = false, isAdmin = false, isMember = false } = {}) {
|
|
26
25
|
if (isOwner) return WORLD_ROLES.OWNER;
|
|
27
|
-
if (isAdmin) return WORLD_ROLES.ADMIN;
|
|
28
26
|
if (isMember) return WORLD_ROLES.MEMBER;
|
|
29
27
|
return WORLD_ROLES.NONE;
|
|
30
28
|
}
|
|
@@ -34,12 +32,12 @@ function resolveActionRequirement(action) {
|
|
|
34
32
|
case WORLD_ACTIONS.VIEW_MANAGEMENT:
|
|
35
33
|
case WORLD_ACTIONS.MANAGE_WORLD:
|
|
36
34
|
case WORLD_ACTIONS.BROADCAST:
|
|
35
|
+
case WORLD_ACTIONS.CHANGE_ENABLED_STATE:
|
|
37
36
|
return {
|
|
38
|
-
allowedRoles: [WORLD_ROLES.OWNER
|
|
39
|
-
reason: '
|
|
37
|
+
allowedRoles: [WORLD_ROLES.OWNER],
|
|
38
|
+
reason: 'owner_role_required',
|
|
40
39
|
};
|
|
41
40
|
case WORLD_ACTIONS.MANAGE_WORLD_ROLES:
|
|
42
|
-
case WORLD_ACTIONS.CHANGE_ENABLED_STATE:
|
|
43
41
|
return {
|
|
44
42
|
allowedRoles: [WORLD_ROLES.OWNER],
|
|
45
43
|
reason: 'owner_role_required',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { authenticateAppTokenRequest, resolveAuthenticatedAgentId } from '../../lib/http-auth.js';
|
|
2
2
|
import {
|
|
3
3
|
buildCandidateDeliverySummary,
|
|
4
|
-
buildRequiredFieldExplanation,
|
|
5
4
|
buildResolvedWorldJoinOrchestration,
|
|
6
5
|
buildWorldSelectionPrompt,
|
|
7
6
|
} from '../contracts/world-orchestration.js';
|
|
@@ -103,7 +102,7 @@ export function registerWorldRoutes(
|
|
|
103
102
|
searchService,
|
|
104
103
|
worldBroadcastService,
|
|
105
104
|
worldAdminService,
|
|
106
|
-
|
|
105
|
+
worldConversationOrchestrator,
|
|
107
106
|
},
|
|
108
107
|
) {
|
|
109
108
|
function resolveAgentIdentity(req, res, { providedAgentId = null, fieldName = 'agentId', required = true } = {}) {
|
|
@@ -175,17 +174,8 @@ export function registerWorldRoutes(
|
|
|
175
174
|
try {
|
|
176
175
|
const result = await worldAdminService.createWorld({
|
|
177
176
|
ownerAgentId,
|
|
178
|
-
adminAgentIds: req.body?.adminAgentIds,
|
|
179
|
-
eligibility: req.body?.eligibility,
|
|
180
|
-
broadcast: req.body?.broadcast,
|
|
181
177
|
displayName: req.body?.displayName,
|
|
182
|
-
|
|
183
|
-
description: req.body?.description,
|
|
184
|
-
entryProfileSchema: req.body?.entryProfileSchema,
|
|
185
|
-
interactionRules: req.body?.interactionRules,
|
|
186
|
-
prohibitedRules: req.body?.prohibitedRules,
|
|
187
|
-
ratingRules: req.body?.ratingRules,
|
|
188
|
-
sessionTemplate: req.body?.sessionTemplate,
|
|
178
|
+
worldContextText: req.body?.worldContextText,
|
|
189
179
|
enabled: req.body?.enabled,
|
|
190
180
|
});
|
|
191
181
|
res.status(201).json(result);
|
|
@@ -197,12 +187,7 @@ export function registerWorldRoutes(
|
|
|
197
187
|
app.get('/v1/worlds/:worldId', (req, res) => {
|
|
198
188
|
try {
|
|
199
189
|
const detail = worldService.describeWorldDetail(req.params.worldId);
|
|
200
|
-
|
|
201
|
-
res.json({
|
|
202
|
-
...detail,
|
|
203
|
-
matching: matchmakingService.describeStrategy(world.worldId),
|
|
204
|
-
requiredFieldExplanation: buildRequiredFieldExplanation(detail),
|
|
205
|
-
});
|
|
190
|
+
res.json(detail);
|
|
206
191
|
} catch (error) {
|
|
207
192
|
sendWorldError(res, error);
|
|
208
193
|
}
|
|
@@ -269,19 +254,6 @@ export function registerWorldRoutes(
|
|
|
269
254
|
}
|
|
270
255
|
});
|
|
271
256
|
|
|
272
|
-
app.post('/v1/worlds/:worldId/join-check', (req, res) => {
|
|
273
|
-
try {
|
|
274
|
-
const result = membershipService.evaluateJoin({
|
|
275
|
-
worldId: req.params.worldId,
|
|
276
|
-
profile: req.body?.profile,
|
|
277
|
-
maxFieldsPerStep: req.body?.maxFieldsPerStep,
|
|
278
|
-
});
|
|
279
|
-
res.status(result.accepted ? 200 : 422).json(result);
|
|
280
|
-
} catch (error) {
|
|
281
|
-
sendWorldError(res, error);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
257
|
app.post('/v1/worlds/:worldId/join', async (req, res) => {
|
|
286
258
|
const agentId = resolveAgentIdentity(req, res, {
|
|
287
259
|
providedAgentId: req.body?.agentId,
|
|
@@ -292,9 +264,7 @@ export function registerWorldRoutes(
|
|
|
292
264
|
const result = await membershipService.joinWorld({
|
|
293
265
|
worldId: req.params.worldId,
|
|
294
266
|
agentId,
|
|
295
|
-
|
|
296
|
-
profileSnapshot: req.body?.profileSnapshot,
|
|
297
|
-
maxFieldsPerStep: req.body?.maxFieldsPerStep,
|
|
267
|
+
participantContextText: req.body?.participantContextText,
|
|
298
268
|
});
|
|
299
269
|
const worldDetail = worldService.describeWorldDetail(req.params.worldId);
|
|
300
270
|
const candidateFeed = matchmakingService.listCandidateFeed({
|
|
@@ -357,7 +327,7 @@ export function registerWorldRoutes(
|
|
|
357
327
|
const result = await membershipService.createMembership({
|
|
358
328
|
worldId: req.params.worldId,
|
|
359
329
|
agentId,
|
|
360
|
-
|
|
330
|
+
participantContextText: req.body?.participantContextText,
|
|
361
331
|
});
|
|
362
332
|
res.status(result.created ? 201 : 200).json(result.membership);
|
|
363
333
|
} catch (error) {
|
|
@@ -365,11 +335,11 @@ export function registerWorldRoutes(
|
|
|
365
335
|
}
|
|
366
336
|
});
|
|
367
337
|
|
|
368
|
-
app.post('/v1/worlds/:worldId/
|
|
338
|
+
app.post('/v1/worlds/:worldId/conversation-preview', (req, res) => {
|
|
369
339
|
try {
|
|
370
|
-
const result =
|
|
340
|
+
const result = worldConversationOrchestrator.previewConversation({
|
|
371
341
|
worldId: req.params.worldId,
|
|
372
|
-
|
|
342
|
+
conversationKey: req.body?.conversationKey,
|
|
373
343
|
});
|
|
374
344
|
res.json(result);
|
|
375
345
|
} catch (error) {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
projectWorldCard,
|
|
4
4
|
projectWorldDetail,
|
|
5
5
|
projectJoinPlan,
|
|
6
|
-
|
|
6
|
+
projectConversationWorldContext,
|
|
7
7
|
} from '../contracts/world-manifest.js';
|
|
8
8
|
import { DEFAULT_WORLD_MANIFESTS } from '../catalog/default-world-catalog.js';
|
|
9
9
|
|
|
@@ -75,8 +75,8 @@ export function createWorldService({ worldCatalog = DEFAULT_WORLD_MANIFESTS, sto
|
|
|
75
75
|
buildJoinPlan(worldId) {
|
|
76
76
|
return projectJoinPlan(this.requireWorld(worldId));
|
|
77
77
|
},
|
|
78
|
-
|
|
79
|
-
return
|
|
78
|
+
describeConversationWorldContext(worldId) {
|
|
79
|
+
return projectConversationWorldContext(this.requireWorld(worldId));
|
|
80
80
|
},
|
|
81
81
|
describeCatalog() {
|
|
82
82
|
return {
|