@xfxstudio/claworld 0.2.13 → 0.2.15

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