@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.
Files changed (55) hide show
  1. package/README.md +12 -29
  2. package/openclaw.plugin.json +9 -33
  3. package/package.json +2 -10
  4. package/skills/claworld-help/SKILL.md +86 -160
  5. package/skills/claworld-join-and-chat/SKILL.md +107 -203
  6. package/skills/claworld-manage-worlds/SKILL.md +75 -392
  7. package/src/lib/chat-request.js +347 -0
  8. package/src/lib/{accepted-chat-kickoff.js → relay/kickoff-text.js} +67 -26
  9. package/src/openclaw/index.js +0 -5
  10. package/src/openclaw/installer/cli.js +14 -16
  11. package/src/openclaw/installer/core.js +13 -14
  12. package/src/openclaw/installer/doctor.js +69 -31
  13. package/src/openclaw/installer/workspace-contract.js +33 -9
  14. package/src/openclaw/plugin/claworld-channel-plugin.js +156 -625
  15. package/src/openclaw/plugin/config-schema.js +4 -16
  16. package/src/openclaw/plugin/managed-config.js +127 -75
  17. package/src/openclaw/plugin/onboarding.js +7 -3
  18. package/src/openclaw/plugin/register.js +40 -339
  19. package/src/openclaw/plugin/relay-client.js +112 -102
  20. package/src/openclaw/protocol/relay-event-protocol.js +34 -22
  21. package/src/openclaw/runtime/canonical-result-builder.js +15 -5
  22. package/src/openclaw/runtime/demo-session-bootstrap.js +0 -4
  23. package/src/openclaw/runtime/feedback-helper.js +3 -2
  24. package/src/openclaw/runtime/inbound-session-router.js +28 -20
  25. package/src/openclaw/runtime/outbound-session-bridge.js +21 -9
  26. package/src/openclaw/runtime/product-shell-helper.js +45 -637
  27. package/src/openclaw/runtime/runtime-path.js +2 -2
  28. package/src/openclaw/runtime/system-message-orchestrator.js +1 -1
  29. package/src/openclaw/runtime/tool-contracts.js +36 -258
  30. package/src/openclaw/runtime/world-moderation-helper.js +11 -65
  31. package/src/product-shell/catalog/default-world-catalog.js +15 -33
  32. package/src/product-shell/contracts/candidate-feed.js +40 -5
  33. package/src/product-shell/contracts/chat-request-approval-policy.js +3 -3
  34. package/src/product-shell/contracts/world-manifest.js +134 -161
  35. package/src/product-shell/contracts/world-orchestration.js +55 -326
  36. package/src/product-shell/feedback/feedback-routes.js +4 -3
  37. package/src/product-shell/feedback/feedback-service.js +11 -8
  38. package/src/product-shell/index.js +6 -7
  39. package/src/product-shell/matching/matchmaking-service.js +39 -5
  40. package/src/product-shell/membership/membership-service.js +125 -147
  41. package/src/product-shell/onboarding/onboarding-service.js +2 -2
  42. package/src/product-shell/orchestration/world-conversation-orchestrator.js +30 -0
  43. package/src/product-shell/orchestration/world-conversation-text.js +231 -0
  44. package/src/product-shell/results/result-service.js +9 -3
  45. package/src/product-shell/search/search-service.js +28 -1
  46. package/src/product-shell/social/chat-request-routes.js +0 -1
  47. package/src/product-shell/social/chat-request-service.js +1 -102
  48. package/src/product-shell/worlds/world-admin-service.js +86 -277
  49. package/src/product-shell/worlds/world-authorization.js +3 -5
  50. package/src/product-shell/worlds/world-routes.js +8 -38
  51. package/src/product-shell/worlds/world-service.js +3 -3
  52. package/src/product-shell/worlds/world-text.js +77 -0
  53. package/src/lib/runtime-guidance.js +0 -457
  54. package/src/openclaw/runtime/world-session-startup.js +0 -1
  55. package/src/product-shell/orchestration/session-orchestrator.js +0 -38
@@ -7,6 +7,7 @@ export const CANDIDATE_OBJECT_FIELDS = Object.freeze([
7
7
  'worldId',
8
8
  'targetAgentId',
9
9
  'sourceMembershipId',
10
+ 'online',
10
11
  'requestChat',
11
12
  'profileSummary',
12
13
  'compatibilitySignals',
@@ -100,6 +101,16 @@ function normalizeComparableText(value) {
100
101
  return normalizeText(value, null)?.toLowerCase() || null;
101
102
  }
102
103
 
104
+ function tokenizeText(value) {
105
+ return [...new Set(
106
+ String(value || '')
107
+ .toLowerCase()
108
+ .split(/[^a-z0-9\u4e00-\u9fff]+/i)
109
+ .map((entry) => entry.trim())
110
+ .filter((entry) => entry.length >= 2),
111
+ )];
112
+ }
113
+
103
114
  function projectSummaryField(field = {}, profile = {}) {
104
115
  const normalizedValue = normalizeValue(profile[field.fieldId], field);
105
116
  if (normalizedValue == null) return null;
@@ -115,7 +126,7 @@ function projectSummaryField(field = {}, profile = {}) {
115
126
  function projectProfileSummary(world, profile = {}, agent = null) {
116
127
  return {
117
128
  displayName: normalizeText(agent?.displayName, null),
118
- headline: normalizeText(profile.headline, null),
129
+ headline: normalizeText(profile.participantContextText, normalizeText(profile.headline, null)),
119
130
  requiredFields: world.joinSchema.requiredFields
120
131
  .map((field) => projectSummaryField(field, profile))
121
132
  .filter(Boolean),
@@ -136,6 +147,21 @@ function createCompatibilitySignal({ sourceMembershipId, type, fieldIds, score,
136
147
  }
137
148
 
138
149
  function compareFieldValues(field, viewerValue, candidateValue, sourceMembershipId) {
150
+ if (field.fieldId === 'participantContextText') {
151
+ const viewerTokens = tokenizeText(viewerValue);
152
+ const candidateTokens = tokenizeText(candidateValue);
153
+ const sharedItems = viewerTokens.filter((item) => candidateTokens.includes(item));
154
+ if (sharedItems.length === 0) return null;
155
+
156
+ return createCompatibilitySignal({
157
+ sourceMembershipId,
158
+ type: 'field_overlap',
159
+ fieldIds: [field.fieldId],
160
+ score: Math.min(sharedItems.length * 0.08, 0.48),
161
+ summary: `Shared context: ${sharedItems.slice(0, 6).join(', ')}.`,
162
+ });
163
+ }
164
+
139
165
  if (field.type === 'string[]') {
140
166
  const viewerItems = normalizeComparableArray(viewerValue);
141
167
  const candidateItems = normalizeComparableArray(candidateValue);
@@ -180,7 +206,7 @@ function buildCompatibilitySignals(world, viewerProfile = {}, candidateProfile =
180
206
  type: 'world_ready',
181
207
  fieldIds: [],
182
208
  score: 0.05,
183
- summary: 'Candidate has an active world membership and is ready for agent review before live session handoff.',
209
+ summary: 'Candidate is online with an active world membership and is ready for agent review before live session handoff.',
184
210
  }),
185
211
  ];
186
212
  }
@@ -192,7 +218,7 @@ function buildDeliveryReason(signals = []) {
192
218
  return {
193
219
  code: 'world_membership_ready',
194
220
  matchedFieldIds: [],
195
- summary: 'Delivered for manual review because the candidate is active in this world, even though no direct profile overlap signal was detected yet.',
221
+ summary: 'Delivered for manual review because the candidate is online and active in this world, even though no direct profile overlap signal was detected yet.',
196
222
  };
197
223
  }
198
224
 
@@ -264,7 +290,7 @@ export function projectCandidateFeedModel(world) {
264
290
  },
265
291
  liveDeliveryEvent: projectLiveDeliveryEvent(world, candidateFields),
266
292
  summary:
267
- 'Active members can review candidate opportunities first, then call request_chat with the selected targetAgentId when they want to start a world-scoped conversation request.',
293
+ 'Active online members can review candidate opportunities first, then call request_chat with the selected targetAgentId when they want to start a world-scoped conversation request.',
268
294
  status: 'phase1_candidate_feed',
269
295
  };
270
296
  }
@@ -274,6 +300,7 @@ function projectCandidateOpportunity({
274
300
  viewerProfile,
275
301
  candidateMembership,
276
302
  candidateAgent,
303
+ candidatePresence,
277
304
  expiresAt,
278
305
  }) {
279
306
  const profileSnapshot = candidateMembership.profileSnapshot || {};
@@ -290,6 +317,7 @@ function projectCandidateOpportunity({
290
317
  worldId: world.worldId,
291
318
  sourceMembershipId: candidateMembership.membershipId,
292
319
  targetAgentId: requestChat?.targetAgentId || null,
320
+ online: candidatePresence?.online === true,
293
321
  requestChat,
294
322
  profileSummary: projectProfileSummary(world, profileSnapshot, candidateAgent),
295
323
  compatibilitySignals,
@@ -304,6 +332,7 @@ export function buildCandidateFeed({
304
332
  viewerAgent = null,
305
333
  candidateMemberships = [],
306
334
  getAgent = () => null,
335
+ getPresence = () => ({ online: true }),
307
336
  nowMs = Date.now(),
308
337
  limit = DEFAULT_CANDIDATE_FEED_LIMIT,
309
338
  }) {
@@ -315,12 +344,18 @@ export function buildCandidateFeed({
315
344
 
316
345
  const candidates = candidateMemberships
317
346
  .filter((membership) => membership?.status === 'active' && membership.membershipId !== viewerMembership.membershipId)
318
- .map((membership) => {
347
+ .map((membership) => ({
348
+ membership,
349
+ candidatePresence: getPresence(membership.agentId),
350
+ }))
351
+ .filter(({ candidatePresence }) => candidatePresence?.online === true)
352
+ .map(({ membership, candidatePresence }) => {
319
353
  const opportunity = projectCandidateOpportunity({
320
354
  world,
321
355
  viewerProfile,
322
356
  candidateMembership: membership,
323
357
  candidateAgent: getAgent(membership.agentId),
358
+ candidatePresence,
324
359
  expiresAt,
325
360
  });
326
361
 
@@ -1,4 +1,4 @@
1
- const DEFAULT_MODE = 'manual_review';
1
+ const DEFAULT_MODE = 'open';
2
2
  const SUPPORTED_MODES = Object.freeze([
3
3
  DEFAULT_MODE,
4
4
  'world_only',
@@ -45,7 +45,7 @@ export function normalizeChatRequestApprovalMode(value, fallback = DEFAULT_MODE)
45
45
  case 'manual':
46
46
  case 'manual_review':
47
47
  case 'review':
48
- return DEFAULT_MODE;
48
+ return 'manual_review';
49
49
  case 'world':
50
50
  case 'world_only':
51
51
  return 'world_only';
@@ -88,7 +88,7 @@ export function normalizeChatRequestApprovalPolicy(
88
88
  : normalizedLegacyAutoAccept === true
89
89
  ? 'open'
90
90
  : normalizedLegacyAutoAccept === false
91
- ? DEFAULT_MODE
91
+ ? 'manual_review'
92
92
  : normalizeChatRequestApprovalMode(fallbackMode, DEFAULT_MODE);
93
93
 
94
94
  return {
@@ -1,5 +1,6 @@
1
1
  import { projectCandidateFeedModel } from './candidate-feed.js';
2
2
  import { buildWorldSessionStartupText } from './world-orchestration.js';
3
+ import { buildWorldContextText } from '../worlds/world-text.js';
3
4
 
4
5
  function normalizeText(value, fallback = null) {
5
6
  if (value == null) return fallback;
@@ -12,6 +13,24 @@ function normalizeStringList(values = []) {
12
13
  return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
13
14
  }
14
15
 
16
+ function normalizeCandidateSource(value) {
17
+ const normalized = normalizeText(value, null);
18
+ if (!normalized) return null;
19
+ if (
20
+ normalized === 'active_memberships'
21
+ || normalized === 'world_members'
22
+ || normalized === 'search_results'
23
+ ) {
24
+ return 'active_memberships_online';
25
+ }
26
+ return normalized;
27
+ }
28
+
29
+ function normalizeCandidateSources(values = []) {
30
+ if (!Array.isArray(values)) return [];
31
+ return [...new Set(values.map((value) => normalizeCandidateSource(value)).filter(Boolean))];
32
+ }
33
+
15
34
  function normalizeWorldEligibility(value, fallback = 'active') {
16
35
  const normalized = normalizeText(value, fallback);
17
36
  if (normalized === 'joined') return 'joined';
@@ -78,17 +97,21 @@ function normalizeExampleSignals(exampleSignals = {}) {
78
97
  }
79
98
 
80
99
  function normalizeJoinSchema(joinSchema = {}) {
81
- const requiredFields = Array.isArray(joinSchema.requiredFields)
82
- ? joinSchema.requiredFields.map((field, index) => normalizeField(field, index, { required: true }))
83
- : [];
84
- const optionalFields = Array.isArray(joinSchema.optionalFields)
85
- ? joinSchema.optionalFields.map((field, index) => normalizeField(field, index, { required: false }))
86
- : [];
87
-
88
100
  return {
89
- requiredFields,
90
- optionalFields,
91
- hints: normalizeStringList(joinSchema.hints),
101
+ requiredFields: [
102
+ {
103
+ fieldId: 'participantContextText',
104
+ label: 'Entry Profile',
105
+ type: 'string',
106
+ source: 'membership',
107
+ required: true,
108
+ description: 'Free-form participant profile/context text used for world join, search, and candidate review.',
109
+ examples: [],
110
+ constraints: {},
111
+ },
112
+ ],
113
+ optionalFields: [],
114
+ hints: [],
92
115
  };
93
116
  }
94
117
 
@@ -139,12 +162,25 @@ function normalizeSearchSchema(searchSchema = {}, joinSchema = {}) {
139
162
  };
140
163
  }
141
164
 
165
+ function resolveConversationTemplateInput(manifest = {}) {
166
+ if (manifest.conversationTemplate && typeof manifest.conversationTemplate === 'object' && !Array.isArray(manifest.conversationTemplate)) {
167
+ return manifest.conversationTemplate;
168
+ }
169
+ return {};
170
+ }
171
+
142
172
  export function normalizeWorldManifest(manifest = {}, index = 0) {
143
173
  const worldId = normalizeText(manifest.worldId || manifest.id, `world_${index + 1}`);
144
174
  const joinSchema = normalizeJoinSchema(manifest.joinSchema);
145
175
  const searchSchema = normalizeSearchSchema(manifest.searchSchema, joinSchema);
146
- const defaultInteractionRules = normalizeText(manifest.sessionTemplate?.worldRules?.openingText, null);
147
- const defaultProhibitedRules = normalizeText(manifest.sessionTemplate?.raiseHandPolicy?.summary, null);
176
+ const conversationTemplate = resolveConversationTemplateInput(manifest);
177
+ const defaultInteractionRules = normalizeText(conversationTemplate?.worldRules?.openingText, null);
178
+ const normalizedInteractionRules = normalizeText(manifest.interactionRules, defaultInteractionRules);
179
+ const normalizedProhibitedRules = normalizeText(manifest.prohibitedRules, null);
180
+ const normalizedRatingRules = normalizeText(
181
+ manifest.ratingRules,
182
+ 'After the interaction ends, each agent should rate the other participant from 1 to 10 based on fit, clarity, and rule compliance.',
183
+ );
148
184
 
149
185
  return {
150
186
  worldId,
@@ -155,12 +191,21 @@ export function normalizeWorldManifest(manifest = {}, index = 0) {
155
191
  category: normalizeText(manifest.category, 'general'),
156
192
  lifecycle: normalizeText(manifest.lifecycle, 'scaffold'),
157
193
  tags: normalizeStringList(manifest.tags),
158
- interactionRules: normalizeText(manifest.interactionRules, defaultInteractionRules),
159
- prohibitedRules: normalizeText(manifest.prohibitedRules, defaultProhibitedRules),
160
- ratingRules: normalizeText(
161
- manifest.ratingRules,
162
- 'After the interaction ends, each agent should rate the other participant from 1 to 10 based on fit, clarity, and rule compliance.',
163
- ),
194
+ interactionRules: normalizedInteractionRules,
195
+ prohibitedRules: normalizedProhibitedRules,
196
+ ratingRules: normalizedRatingRules,
197
+ worldContextText: buildWorldContextText({
198
+ worldId,
199
+ displayName: normalizeText(manifest.displayName, worldId),
200
+ summary: normalizeText(manifest.summary, null),
201
+ worldContextText: normalizeText(
202
+ manifest.worldContextText,
203
+ normalizeText(manifest.runtimeWorldContext?.text, null),
204
+ ),
205
+ interactionRules: normalizedInteractionRules,
206
+ prohibitedRules: normalizedProhibitedRules,
207
+ ratingRules: normalizedRatingRules,
208
+ }),
164
209
  creatorAgentId: normalizeText(manifest.creatorAgentId, null),
165
210
  adminAgentIds: normalizeStringList(manifest.adminAgentIds),
166
211
  eligibility: normalizeWorldEligibility(manifest.eligibility, 'active'),
@@ -188,27 +233,17 @@ export function normalizeWorldManifest(manifest = {}, index = 0) {
188
233
  mode: normalizeText(manifest.matching?.mode, 'manual_review'),
189
234
  cadence: normalizeText(manifest.matching?.cadence, 'on_demand'),
190
235
  strategySummary: normalizeText(manifest.matching?.strategySummary, null),
191
- candidateSources: normalizeStringList(manifest.matching?.candidateSources),
236
+ candidateSources: normalizeCandidateSources(manifest.matching?.candidateSources),
192
237
  },
193
- sessionTemplate: {
194
- mode: normalizeText(manifest.sessionTemplate?.mode, 'a2a'),
195
- maxTurns: Number.isFinite(Number(manifest.sessionTemplate?.maxTurns))
196
- ? Math.max(1, Number(manifest.sessionTemplate.maxTurns))
197
- : 6,
198
- turnTimeoutMs: Number.isFinite(Number(manifest.sessionTemplate?.turnTimeoutMs))
199
- ? Math.max(1000, Number(manifest.sessionTemplate.turnTimeoutMs))
200
- : 60_000,
201
- raiseHandPolicy: {
202
- mode: normalizeText(manifest.sessionTemplate?.raiseHandPolicy?.mode, 'dual_raise_hand'),
203
- summary: normalizeText(manifest.sessionTemplate?.raiseHandPolicy?.summary, null),
204
- },
238
+ conversationTemplate: {
239
+ mode: normalizeText(conversationTemplate?.mode, 'a2a'),
205
240
  worldRules: {
206
- openingText: normalizeText(manifest.sessionTemplate?.worldRules?.openingText, null),
207
- turnMessageRules: Array.isArray(manifest.sessionTemplate?.worldRules?.turnMessageRules)
208
- ? manifest.sessionTemplate.worldRules.turnMessageRules
241
+ openingText: normalizeText(conversationTemplate?.worldRules?.openingText, null),
242
+ turnMessageRules: Array.isArray(conversationTemplate?.worldRules?.turnMessageRules)
243
+ ? conversationTemplate.worldRules.turnMessageRules
209
244
  : [],
210
- convergence: manifest.sessionTemplate?.worldRules?.convergence || {},
211
- stateChangeMessages: manifest.sessionTemplate?.worldRules?.stateChangeMessages || {},
245
+ convergence: conversationTemplate?.worldRules?.convergence || {},
246
+ stateChangeMessages: conversationTemplate?.worldRules?.stateChangeMessages || {},
212
247
  },
213
248
  },
214
249
  resultContract: {
@@ -225,40 +260,26 @@ export function normalizeWorldManifest(manifest = {}, index = 0) {
225
260
  }
226
261
 
227
262
  export function projectWorldCard(world) {
228
- const agentSummary = {
229
- displayName: world.displayName,
230
- summary: world.summary,
231
- category: world.category,
232
- requiredFieldCount: world.joinSchema.requiredFields.length,
233
- matchingMode: world.matching.mode,
234
- sessionMode: world.sessionTemplate.mode,
235
- };
236
-
237
263
  return {
238
264
  worldId: world.worldId,
239
265
  slug: world.slug,
240
- displayName: agentSummary.displayName,
241
- summary: agentSummary.summary,
242
- category: agentSummary.category,
243
- lifecycle: world.lifecycle,
244
- tags: world.tags,
245
- requiredFieldCount: agentSummary.requiredFieldCount,
246
- roleCount: world.roles.length,
247
- matchingMode: agentSummary.matchingMode,
248
- sessionMode: agentSummary.sessionMode,
266
+ displayName: world.displayName,
267
+ worldContextText: world.worldContextText,
249
268
  createdAt: world.createdAt || null,
250
269
  updatedAt: world.updatedAt || null,
251
- status: world.meta.status,
252
- agentSummary,
270
+ status: world.status || world.meta.status,
271
+ enabled: world.enabled === true,
253
272
  };
254
273
  }
255
274
 
256
275
  export function projectJoinPlan(world) {
257
276
  return {
258
277
  worldId: world.worldId,
259
- requiredFields: world.joinSchema.requiredFields,
260
- optionalFields: world.joinSchema.optionalFields,
261
- hints: world.joinSchema.hints,
278
+ participantContextField: {
279
+ fieldId: 'participantContextText',
280
+ label: 'Entry Profile',
281
+ description: 'A short text describing who you are in this world and what context you bring into it.',
282
+ },
262
283
  nextAction: 'call_join_world',
263
284
  };
264
285
  }
@@ -296,140 +317,92 @@ export function projectSearchModel(world) {
296
317
 
297
318
  export function projectWorldDetail(world) {
298
319
  const joinPlan = projectJoinPlan(world);
299
- const requiredFieldGuide = projectFieldGuide(world.joinSchema.requiredFields, { required: true });
300
- const optionalFieldGuide = projectFieldGuide(world.joinSchema.optionalFields, { required: false });
301
- const allFieldGuide = [...requiredFieldGuide, ...optionalFieldGuide];
302
- const candidateFeedOverview = projectCandidateFeedModel(world);
303
- const searchSchema = projectSearchModel(world);
304
- const runtimeStartupContext = {
305
- worldId: world.worldId,
306
- status: 'ready',
307
- source: 'product_shell_session_startup',
308
- text: buildWorldSessionStartupText({
320
+ const worldContextText = normalizeText(
321
+ world.worldContextText,
322
+ buildWorldSessionStartupText({
309
323
  worldId: world.worldId,
310
324
  displayName: world.displayName,
311
325
  summary: world.summary,
312
326
  interactionRules: world.interactionRules,
313
327
  prohibitedRules: world.prohibitedRules,
314
328
  ratingRules: world.ratingRules,
315
- sessionMode: world.sessionTemplate.mode,
316
- sessionOverview: {
329
+ conversationMode: world.conversationTemplate.mode,
330
+ conversationOverview: {
317
331
  worldId: world.worldId,
318
- mode: world.sessionTemplate.mode,
319
- maxTurns: world.sessionTemplate.maxTurns,
320
- turnTimeoutMs: world.sessionTemplate.turnTimeoutMs,
321
- raiseHandPolicy: world.sessionTemplate.raiseHandPolicy,
322
- openingText: world.sessionTemplate.worldRules.openingText,
323
- convergence: world.sessionTemplate.worldRules.convergence,
332
+ mode: world.conversationTemplate.mode,
333
+ openingText: world.conversationTemplate.worldRules.openingText,
334
+ convergence: world.conversationTemplate.worldRules.convergence,
324
335
  },
325
336
  }),
326
- };
337
+ );
327
338
 
328
339
  return {
329
- world: world,
330
- agentSummary: {
331
- displayName: world.displayName,
332
- summary: world.summary,
333
- category: world.category,
334
- requiredFieldCount: world.joinSchema.requiredFields.length,
335
- optionalFieldCount: world.joinSchema.optionalFields.length,
336
- matchingMode: world.matching.mode,
337
- sessionMode: world.sessionTemplate.mode,
338
- },
339
- joinSchema: {
340
- worldId: world.worldId,
341
- requiredFields: world.joinSchema.requiredFields,
342
- optionalFields: world.joinSchema.optionalFields,
343
- requiredFieldIds: requiredFieldGuide.map((field) => field.fieldId),
344
- optionalFieldIds: optionalFieldGuide.map((field) => field.fieldId),
345
- requiredFieldCount: requiredFieldGuide.length,
346
- optionalFieldCount: optionalFieldGuide.length,
347
- hints: world.joinSchema.hints,
348
- nextAction: joinPlan.nextAction,
349
- },
350
- fieldGuide: {
351
- required: requiredFieldGuide,
352
- optional: optionalFieldGuide,
353
- allFields: allFieldGuide,
354
- },
355
- sessionOverview: {
340
+ worldId: world.worldId,
341
+ world: {
356
342
  worldId: world.worldId,
357
- mode: world.sessionTemplate.mode,
358
- maxTurns: world.sessionTemplate.maxTurns,
359
- turnTimeoutMs: world.sessionTemplate.turnTimeoutMs,
360
- raiseHandPolicy: world.sessionTemplate.raiseHandPolicy,
361
- openingText: world.sessionTemplate.worldRules.openingText,
362
- convergence: world.sessionTemplate.worldRules.convergence,
363
- turnMessageRules: world.sessionTemplate.worldRules.turnMessageRules,
364
- expectationSummary:
365
- `Expect a ${world.sessionTemplate.mode} session with up to ${world.sessionTemplate.maxTurns} turns and ` +
366
- `a ${world.sessionTemplate.turnTimeoutMs}ms turn timeout before the world asks both agents to converge.`,
367
- status: 'scaffold_ready',
343
+ displayName: world.displayName,
344
+ worldContextText,
368
345
  },
369
- matchingOverview: {
370
- worldId: world.worldId,
371
- mode: world.matching.mode,
372
- cadence: world.matching.cadence,
373
- strategySummary: world.matching.strategySummary,
374
- candidateSources: world.matching.candidateSources,
375
- inputFields: requiredFieldGuide.map((field) => field.fieldId),
376
- optionalContextFields: optionalFieldGuide.map((field) => field.fieldId),
377
- searchMode: searchSchema.mode,
378
- deliveryMode: candidateFeedOverview.deliveryMode,
379
- status: 'scaffold_ready',
346
+ management: {
347
+ ownerAgentId: world.creatorAgentId || null,
348
+ enabled: world.enabled === true,
349
+ status: world.status || world.meta.status,
350
+ createdAt: world.createdAt || null,
351
+ updatedAt: world.updatedAt || null,
352
+ memberCount: world.metrics?.memberCount || null,
353
+ totalConversationCount: Number.isFinite(Number(world.metrics?.totalConversationCount))
354
+ ? Math.max(0, Math.trunc(Number(world.metrics.totalConversationCount)))
355
+ : 0,
380
356
  },
381
- searchSchema,
382
- candidateFeedOverview,
357
+ participantContextField: joinPlan.participantContextField,
383
358
  joinPlan,
384
- runtimeStartupContext,
359
+ worldContextText,
385
360
  };
386
361
  }
387
362
 
388
- export function projectSessionStartupContext(world) {
389
- const runtimeStartupContext = {
363
+ export function projectConversationWorldContext(world) {
364
+ const runtimeWorldContext = {
390
365
  worldId: world.worldId,
391
366
  status: 'ready',
392
- source: 'product_shell_session_startup',
393
- text: buildWorldSessionStartupText({
394
- worldId: world.worldId,
395
- displayName: world.displayName,
396
- summary: world.summary,
397
- interactionRules: world.interactionRules,
398
- prohibitedRules: world.prohibitedRules,
399
- ratingRules: world.ratingRules,
400
- sessionMode: world.sessionTemplate.mode,
401
- sessionOverview: {
367
+ source: 'product_shell_conversation_world_context',
368
+ text: normalizeText(
369
+ world.worldContextText,
370
+ buildWorldSessionStartupText({
402
371
  worldId: world.worldId,
403
- mode: world.sessionTemplate.mode,
404
- maxTurns: world.sessionTemplate.maxTurns,
405
- turnTimeoutMs: world.sessionTemplate.turnTimeoutMs,
406
- raiseHandPolicy: world.sessionTemplate.raiseHandPolicy,
407
- openingText: world.sessionTemplate.worldRules.openingText,
408
- convergence: world.sessionTemplate.worldRules.convergence,
409
- },
410
- }),
372
+ displayName: world.displayName,
373
+ summary: world.summary,
374
+ interactionRules: world.interactionRules,
375
+ prohibitedRules: world.prohibitedRules,
376
+ ratingRules: world.ratingRules,
377
+ conversationMode: world.conversationTemplate.mode,
378
+ conversationOverview: {
379
+ worldId: world.worldId,
380
+ mode: world.conversationTemplate.mode,
381
+ openingText: world.conversationTemplate.worldRules.openingText,
382
+ convergence: world.conversationTemplate.worldRules.convergence,
383
+ },
384
+ }),
385
+ ),
411
386
  };
412
387
 
413
388
  return {
414
389
  worldId: world.worldId,
415
390
  displayName: world.displayName,
416
391
  summary: world.summary,
392
+ worldContextText: runtimeWorldContext.text,
417
393
  interactionRules: world.interactionRules,
418
394
  prohibitedRules: world.prohibitedRules,
419
395
  ratingRules: world.ratingRules,
420
- sessionMode: world.sessionTemplate.mode,
421
- sessionOverview: {
396
+ conversationMode: world.conversationTemplate.mode,
397
+ conversationOverview: {
422
398
  worldId: world.worldId,
423
- mode: world.sessionTemplate.mode,
424
- maxTurns: world.sessionTemplate.maxTurns,
425
- turnTimeoutMs: world.sessionTemplate.turnTimeoutMs,
426
- raiseHandPolicy: world.sessionTemplate.raiseHandPolicy,
427
- openingText: world.sessionTemplate.worldRules.openingText,
428
- convergence: world.sessionTemplate.worldRules.convergence,
429
- turnMessageRules: world.sessionTemplate.worldRules.turnMessageRules,
399
+ mode: world.conversationTemplate.mode,
400
+ openingText: world.conversationTemplate.worldRules.openingText,
401
+ convergence: world.conversationTemplate.worldRules.convergence,
402
+ turnMessageRules: world.conversationTemplate.worldRules.turnMessageRules,
430
403
  },
431
404
  status: 'ready',
432
- source: 'product_shell_session_startup',
433
- runtimeStartupContext,
405
+ source: 'product_shell_conversation_world_context',
406
+ runtimeWorldContext,
434
407
  };
435
408
  }