@xfxstudio/claworld 0.2.13 → 0.2.14
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 +4 -4
- package/index.js +0 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/claworld-help/SKILL.md +19 -27
- package/skills/claworld-join-and-chat/SKILL.md +9 -9
- package/src/openclaw/index.js +0 -3
- package/src/openclaw/plugin/account-identity.js +0 -1
- package/src/openclaw/plugin/claworld-channel-plugin.js +8 -253
- package/src/openclaw/plugin/managed-config.js +1 -7
- package/src/openclaw/plugin/onboarding.js +1 -1
- package/src/openclaw/plugin/register.js +183 -232
- package/src/openclaw/plugin/relay-client.js +8 -5
- package/src/openclaw/runtime/product-shell-helper.js +11 -364
- package/src/openclaw/runtime/tool-contracts.js +0 -182
- package/src/openclaw/runtime/tool-inventory.js +4 -27
- package/src/lib/agent-profile.js +0 -74
- package/src/lib/http-auth.js +0 -151
- package/src/lib/policy.js +0 -114
- package/src/openclaw/installer/constants.js +0 -14
- package/src/product-shell/agent-cards/card-routes.js +0 -64
- package/src/product-shell/agent-cards/card-service.js +0 -287
- package/src/product-shell/agent-cards/spec-builder.js +0 -167
- package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
- package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
- package/src/product-shell/agent-cards/svg-renderer.js +0 -325
- package/src/product-shell/agent-cards/template-registry.js +0 -131
- package/src/product-shell/catalog/default-world-catalog.js +0 -38
- package/src/product-shell/contracts/candidate-feed.js +0 -393
- package/src/product-shell/contracts/world-manifest.js +0 -369
- package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
- package/src/product-shell/feedback/feedback-contract.js +0 -13
- package/src/product-shell/feedback/feedback-routes.js +0 -98
- package/src/product-shell/feedback/feedback-service.js +0 -252
- package/src/product-shell/index.js +0 -212
- package/src/product-shell/matching/matchmaking-service.js +0 -395
- package/src/product-shell/membership/membership-service.js +0 -284
- package/src/product-shell/onboarding/onboarding-routes.js +0 -37
- package/src/product-shell/onboarding/onboarding-service.js +0 -222
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
- package/src/product-shell/profile/profile-service.js +0 -142
- package/src/product-shell/profile/public-identity-routes.js +0 -160
- package/src/product-shell/profile/public-identity-service.js +0 -192
- package/src/product-shell/search/search-service.js +0 -393
- package/src/product-shell/social/chat-request-approval-policy.js +0 -332
- package/src/product-shell/social/chat-request-routes.js +0 -130
- package/src/product-shell/social/chat-request-service.js +0 -723
- package/src/product-shell/social/friend-routes.js +0 -82
- package/src/product-shell/social/friend-service.js +0 -557
- package/src/product-shell/social/social-routes.js +0 -21
- package/src/product-shell/social/social-service.js +0 -136
- package/src/product-shell/worlds/world-admin-service.js +0 -486
- package/src/product-shell/worlds/world-authorization.js +0 -136
- package/src/product-shell/worlds/world-broadcast-service.js +0 -296
- package/src/product-shell/worlds/world-routes.js +0 -403
- package/src/product-shell/worlds/world-service.js +0 -89
- package/src/product-shell/worlds/world-text.js +0 -75
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
import { projectCandidateFeedModel } from './candidate-feed.js';
|
|
2
|
-
import { buildWorldSessionStartupText } from './world-orchestration.js';
|
|
3
|
-
import { buildWorldContextText } from '../worlds/world-text.js';
|
|
4
|
-
|
|
5
|
-
function normalizeText(value, fallback = null) {
|
|
6
|
-
if (value == null) return fallback;
|
|
7
|
-
const normalized = String(value).trim();
|
|
8
|
-
return normalized || fallback;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function normalizeStringList(values = []) {
|
|
12
|
-
if (!Array.isArray(values)) return [];
|
|
13
|
-
return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
|
|
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
|
-
|
|
34
|
-
function normalizeWorldEligibility(value, fallback = 'active') {
|
|
35
|
-
const normalized = normalizeText(value, fallback);
|
|
36
|
-
if (normalized === 'joined') return 'joined';
|
|
37
|
-
return 'active';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function normalizeBroadcastAudience(value, fallback = 'members') {
|
|
41
|
-
const normalized = normalizeText(value, fallback);
|
|
42
|
-
if (normalized === 'admins') return 'admins';
|
|
43
|
-
if (normalized === 'admins_and_owner') return 'admins_and_owner';
|
|
44
|
-
return 'members';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function normalizeBroadcastReplyPolicy(value, fallback = 'zero') {
|
|
48
|
-
const normalized = normalizeText(value, fallback);
|
|
49
|
-
if (normalized === 'at_most_one') return 'at_most_one';
|
|
50
|
-
return 'zero';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function normalizeBroadcastConfig(broadcast = {}, { enabled = false } = {}) {
|
|
54
|
-
const normalized = broadcast && typeof broadcast === 'object' && !Array.isArray(broadcast)
|
|
55
|
-
? broadcast
|
|
56
|
-
: {};
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
enabled: normalized.enabled === true || enabled === true,
|
|
60
|
-
audience: normalizeBroadcastAudience(normalized.audience, 'members'),
|
|
61
|
-
replyPolicy: normalizeBroadcastReplyPolicy(normalized.replyPolicy, 'zero'),
|
|
62
|
-
excludeSelf: normalized.excludeSelf !== false,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function normalizeField(field = {}, index = 0, { required = false } = {}) {
|
|
67
|
-
const fieldId = normalizeText(field.fieldId || field.id, `field_${index + 1}`);
|
|
68
|
-
return {
|
|
69
|
-
fieldId,
|
|
70
|
-
label: normalizeText(field.label, fieldId),
|
|
71
|
-
type: normalizeText(field.type, 'string'),
|
|
72
|
-
source: normalizeText(field.source, 'profile'),
|
|
73
|
-
required: field.required === true || required,
|
|
74
|
-
description: normalizeText(field.description, null),
|
|
75
|
-
examples: normalizeStringList(field.examples),
|
|
76
|
-
constraints: field.constraints && typeof field.constraints === 'object' ? field.constraints : {},
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function normalizeJoinSchema(joinSchema = {}) {
|
|
81
|
-
return {
|
|
82
|
-
requiredFields: [
|
|
83
|
-
{
|
|
84
|
-
fieldId: 'participantContextText',
|
|
85
|
-
label: 'Entry Profile',
|
|
86
|
-
type: 'string',
|
|
87
|
-
source: 'membership',
|
|
88
|
-
required: true,
|
|
89
|
-
description: 'Free-form participant profile/context text used for world join, search, and candidate review.',
|
|
90
|
-
examples: [],
|
|
91
|
-
constraints: {},
|
|
92
|
-
},
|
|
93
|
-
],
|
|
94
|
-
optionalFields: [],
|
|
95
|
-
hints: [],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function normalizeSearchSchema(searchSchema = {}, joinSchema = {}) {
|
|
100
|
-
const fieldLookup = new Map(
|
|
101
|
-
[...joinSchema.requiredFields, ...joinSchema.optionalFields].map((field) => [field.fieldId, field]),
|
|
102
|
-
);
|
|
103
|
-
const rawInputFieldIds = Array.isArray(searchSchema.inputFieldIds)
|
|
104
|
-
? searchSchema.inputFieldIds
|
|
105
|
-
: (Array.isArray(searchSchema.inputFields)
|
|
106
|
-
? searchSchema.inputFields.map((field) => (typeof field === 'string' ? field : field.fieldId || field.id))
|
|
107
|
-
: joinSchema.requiredFields.map((field) => field.fieldId));
|
|
108
|
-
const inputFieldIds = normalizeStringList(rawInputFieldIds);
|
|
109
|
-
const inputFields = inputFieldIds.map((fieldId, index) => {
|
|
110
|
-
const referenced = fieldLookup.get(fieldId);
|
|
111
|
-
if (referenced) return { ...referenced };
|
|
112
|
-
return normalizeField({ fieldId, label: fieldId }, index, { required: false });
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
mode: normalizeText(searchSchema.mode, 'membership_profile_search'),
|
|
117
|
-
inputFieldIds,
|
|
118
|
-
inputFields,
|
|
119
|
-
resultFields: normalizeStringList(
|
|
120
|
-
searchSchema.resultFields || [
|
|
121
|
-
'agentId',
|
|
122
|
-
'playerId',
|
|
123
|
-
'membershipId',
|
|
124
|
-
'worldId',
|
|
125
|
-
'displayName',
|
|
126
|
-
'headline',
|
|
127
|
-
'online',
|
|
128
|
-
'matchedFieldIds',
|
|
129
|
-
'score',
|
|
130
|
-
'profileSummary',
|
|
131
|
-
],
|
|
132
|
-
),
|
|
133
|
-
onlineOnly: searchSchema.onlineOnly !== false,
|
|
134
|
-
defaultLimit: Number.isFinite(Number(searchSchema.defaultLimit))
|
|
135
|
-
? Math.max(1, Math.trunc(Number(searchSchema.defaultLimit)))
|
|
136
|
-
: 10,
|
|
137
|
-
summary: normalizeText(
|
|
138
|
-
searchSchema.summary,
|
|
139
|
-
'Compatibility-only manual search over active online world members. Candidate feed review is the canonical path before request_chat.',
|
|
140
|
-
),
|
|
141
|
-
hints: normalizeStringList(searchSchema.hints),
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function resolveConversationTemplateInput(manifest = {}) {
|
|
146
|
-
if (manifest.conversationTemplate && typeof manifest.conversationTemplate === 'object' && !Array.isArray(manifest.conversationTemplate)) {
|
|
147
|
-
return manifest.conversationTemplate;
|
|
148
|
-
}
|
|
149
|
-
return {};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function normalizeWorldManifest(manifest = {}, index = 0) {
|
|
153
|
-
const worldId = normalizeText(manifest.worldId || manifest.id, `world_${index + 1}`);
|
|
154
|
-
const joinSchema = normalizeJoinSchema(manifest.joinSchema);
|
|
155
|
-
const searchSchema = normalizeSearchSchema(manifest.searchSchema, joinSchema);
|
|
156
|
-
const conversationTemplate = resolveConversationTemplateInput(manifest);
|
|
157
|
-
const defaultInteractionRules = normalizeText(conversationTemplate?.worldRules?.openingText, null);
|
|
158
|
-
const normalizedInteractionRules = normalizeText(manifest.interactionRules, defaultInteractionRules);
|
|
159
|
-
const normalizedProhibitedRules = normalizeText(manifest.prohibitedRules, null);
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
worldId,
|
|
163
|
-
slug: normalizeText(manifest.slug, worldId),
|
|
164
|
-
displayName: normalizeText(manifest.displayName, worldId),
|
|
165
|
-
summary: normalizeText(manifest.summary, null),
|
|
166
|
-
description: normalizeText(manifest.description, normalizeText(manifest.summary, null)),
|
|
167
|
-
category: normalizeText(manifest.category, 'general'),
|
|
168
|
-
lifecycle: normalizeText(manifest.lifecycle, 'scaffold'),
|
|
169
|
-
tags: normalizeStringList(manifest.tags),
|
|
170
|
-
interactionRules: normalizedInteractionRules,
|
|
171
|
-
prohibitedRules: normalizedProhibitedRules,
|
|
172
|
-
worldContextText: buildWorldContextText({
|
|
173
|
-
worldId,
|
|
174
|
-
displayName: normalizeText(manifest.displayName, worldId),
|
|
175
|
-
summary: normalizeText(manifest.summary, null),
|
|
176
|
-
worldContextText: normalizeText(
|
|
177
|
-
manifest.worldContextText,
|
|
178
|
-
normalizeText(manifest.runtimeWorldContext?.text, null),
|
|
179
|
-
),
|
|
180
|
-
interactionRules: normalizedInteractionRules,
|
|
181
|
-
prohibitedRules: normalizedProhibitedRules,
|
|
182
|
-
}),
|
|
183
|
-
creatorAgentId: normalizeText(manifest.creatorAgentId, null),
|
|
184
|
-
eligibility: normalizeWorldEligibility(manifest.eligibility, 'active'),
|
|
185
|
-
broadcast: normalizeBroadcastConfig(manifest.broadcast, {
|
|
186
|
-
enabled: manifest.broadcast?.enabled === true,
|
|
187
|
-
}),
|
|
188
|
-
status: normalizeText(manifest.status, manifest.enabled === true ? 'enabled' : 'draft'),
|
|
189
|
-
enabled: manifest.enabled === true,
|
|
190
|
-
schemaVersion: Number.isFinite(Number(manifest.schemaVersion)) ? Math.max(1, Math.trunc(Number(manifest.schemaVersion))) : 1,
|
|
191
|
-
createdAt: normalizeText(manifest.createdAt, null),
|
|
192
|
-
updatedAt: normalizeText(manifest.updatedAt, null),
|
|
193
|
-
metrics: manifest.metrics && typeof manifest.metrics === 'object'
|
|
194
|
-
? {
|
|
195
|
-
totalConversationCount: Number.isFinite(Number(manifest.metrics.totalConversationCount))
|
|
196
|
-
? Math.max(0, Math.trunc(Number(manifest.metrics.totalConversationCount)))
|
|
197
|
-
: 0,
|
|
198
|
-
}
|
|
199
|
-
: { totalConversationCount: 0 },
|
|
200
|
-
joinSchema,
|
|
201
|
-
searchSchema,
|
|
202
|
-
matching: {
|
|
203
|
-
mode: normalizeText(manifest.matching?.mode, 'manual_review'),
|
|
204
|
-
cadence: normalizeText(manifest.matching?.cadence, 'on_demand'),
|
|
205
|
-
strategySummary: normalizeText(manifest.matching?.strategySummary, null),
|
|
206
|
-
candidateSources: normalizeCandidateSources(manifest.matching?.candidateSources),
|
|
207
|
-
},
|
|
208
|
-
conversationTemplate: {
|
|
209
|
-
mode: normalizeText(conversationTemplate?.mode, 'a2a'),
|
|
210
|
-
worldRules: {
|
|
211
|
-
openingText: normalizeText(conversationTemplate?.worldRules?.openingText, null),
|
|
212
|
-
turnMessageRules: Array.isArray(conversationTemplate?.worldRules?.turnMessageRules)
|
|
213
|
-
? conversationTemplate.worldRules.turnMessageRules
|
|
214
|
-
: [],
|
|
215
|
-
convergence: conversationTemplate?.worldRules?.convergence || {},
|
|
216
|
-
stateChangeMessages: conversationTemplate?.worldRules?.stateChangeMessages || {},
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
meta: {
|
|
220
|
-
status: normalizeText(manifest.meta?.status, 'scaffold_ready'),
|
|
221
|
-
persistence: normalizeText(manifest.meta?.persistence, 'in_memory_catalog'),
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function projectWorldCard(world) {
|
|
227
|
-
return {
|
|
228
|
-
worldId: world.worldId,
|
|
229
|
-
slug: world.slug,
|
|
230
|
-
displayName: world.displayName,
|
|
231
|
-
worldContextText: world.worldContextText,
|
|
232
|
-
createdAt: world.createdAt || null,
|
|
233
|
-
updatedAt: world.updatedAt || null,
|
|
234
|
-
status: world.status || world.meta.status,
|
|
235
|
-
enabled: world.enabled === true,
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function projectJoinPlan(world) {
|
|
240
|
-
return {
|
|
241
|
-
worldId: world.worldId,
|
|
242
|
-
participantContextField: {
|
|
243
|
-
fieldId: 'participantContextText',
|
|
244
|
-
label: 'Entry Profile',
|
|
245
|
-
description: 'A short text describing who you are in this world and what context you bring into it.',
|
|
246
|
-
},
|
|
247
|
-
nextAction: 'call_join_world',
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
function projectFieldGuide(fields = [], { required = false } = {}) {
|
|
252
|
-
return fields.map((field) => ({
|
|
253
|
-
fieldId: field.fieldId,
|
|
254
|
-
label: field.label,
|
|
255
|
-
required,
|
|
256
|
-
type: field.type,
|
|
257
|
-
source: field.source,
|
|
258
|
-
description: field.description,
|
|
259
|
-
examples: field.examples,
|
|
260
|
-
constraints: field.constraints,
|
|
261
|
-
}));
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function projectSearchModel(world) {
|
|
265
|
-
return {
|
|
266
|
-
modelId: `${world.worldId}.search.v1`,
|
|
267
|
-
worldId: world.worldId,
|
|
268
|
-
mode: world.searchSchema.mode,
|
|
269
|
-
previewRoute: `/v1/worlds/${world.worldId}/search`,
|
|
270
|
-
inputFieldIds: world.searchSchema.inputFieldIds,
|
|
271
|
-
inputFields: projectFieldGuide(world.searchSchema.inputFields, { required: false }),
|
|
272
|
-
resultFields: world.searchSchema.resultFields,
|
|
273
|
-
viewerRequirement: 'active_membership',
|
|
274
|
-
onlineOnly: world.searchSchema.onlineOnly,
|
|
275
|
-
defaultLimit: world.searchSchema.defaultLimit,
|
|
276
|
-
summary: world.searchSchema.summary,
|
|
277
|
-
hints: world.searchSchema.hints,
|
|
278
|
-
status: 'compatibility_world_search',
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export function projectWorldDetail(world) {
|
|
283
|
-
const joinPlan = projectJoinPlan(world);
|
|
284
|
-
const worldContextText = normalizeText(
|
|
285
|
-
world.worldContextText,
|
|
286
|
-
buildWorldSessionStartupText({
|
|
287
|
-
worldId: world.worldId,
|
|
288
|
-
displayName: world.displayName,
|
|
289
|
-
summary: world.summary,
|
|
290
|
-
interactionRules: world.interactionRules,
|
|
291
|
-
prohibitedRules: world.prohibitedRules,
|
|
292
|
-
conversationMode: world.conversationTemplate.mode,
|
|
293
|
-
conversationOverview: {
|
|
294
|
-
worldId: world.worldId,
|
|
295
|
-
mode: world.conversationTemplate.mode,
|
|
296
|
-
openingText: world.conversationTemplate.worldRules.openingText,
|
|
297
|
-
convergence: world.conversationTemplate.worldRules.convergence,
|
|
298
|
-
},
|
|
299
|
-
}),
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
worldId: world.worldId,
|
|
304
|
-
world: {
|
|
305
|
-
worldId: world.worldId,
|
|
306
|
-
displayName: world.displayName,
|
|
307
|
-
worldContextText,
|
|
308
|
-
},
|
|
309
|
-
management: {
|
|
310
|
-
ownerAgentId: world.creatorAgentId || null,
|
|
311
|
-
enabled: world.enabled === true,
|
|
312
|
-
status: world.status || world.meta.status,
|
|
313
|
-
createdAt: world.createdAt || null,
|
|
314
|
-
updatedAt: world.updatedAt || null,
|
|
315
|
-
memberCount: world.metrics?.memberCount || null,
|
|
316
|
-
totalConversationCount: Number.isFinite(Number(world.metrics?.totalConversationCount))
|
|
317
|
-
? Math.max(0, Math.trunc(Number(world.metrics.totalConversationCount)))
|
|
318
|
-
: 0,
|
|
319
|
-
},
|
|
320
|
-
participantContextField: joinPlan.participantContextField,
|
|
321
|
-
joinPlan,
|
|
322
|
-
worldContextText,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
export function projectConversationWorldContext(world) {
|
|
327
|
-
const runtimeWorldContext = {
|
|
328
|
-
worldId: world.worldId,
|
|
329
|
-
status: 'ready',
|
|
330
|
-
source: 'product_shell_conversation_world_context',
|
|
331
|
-
text: normalizeText(
|
|
332
|
-
world.worldContextText,
|
|
333
|
-
buildWorldSessionStartupText({
|
|
334
|
-
worldId: world.worldId,
|
|
335
|
-
displayName: world.displayName,
|
|
336
|
-
summary: world.summary,
|
|
337
|
-
interactionRules: world.interactionRules,
|
|
338
|
-
prohibitedRules: world.prohibitedRules,
|
|
339
|
-
conversationMode: world.conversationTemplate.mode,
|
|
340
|
-
conversationOverview: {
|
|
341
|
-
worldId: world.worldId,
|
|
342
|
-
mode: world.conversationTemplate.mode,
|
|
343
|
-
openingText: world.conversationTemplate.worldRules.openingText,
|
|
344
|
-
convergence: world.conversationTemplate.worldRules.convergence,
|
|
345
|
-
},
|
|
346
|
-
}),
|
|
347
|
-
),
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
return {
|
|
351
|
-
worldId: world.worldId,
|
|
352
|
-
displayName: world.displayName,
|
|
353
|
-
summary: world.summary,
|
|
354
|
-
worldContextText: runtimeWorldContext.text,
|
|
355
|
-
interactionRules: world.interactionRules,
|
|
356
|
-
prohibitedRules: world.prohibitedRules,
|
|
357
|
-
conversationMode: world.conversationTemplate.mode,
|
|
358
|
-
conversationOverview: {
|
|
359
|
-
worldId: world.worldId,
|
|
360
|
-
mode: world.conversationTemplate.mode,
|
|
361
|
-
openingText: world.conversationTemplate.worldRules.openingText,
|
|
362
|
-
convergence: world.conversationTemplate.worldRules.convergence,
|
|
363
|
-
turnMessageRules: world.conversationTemplate.worldRules.turnMessageRules,
|
|
364
|
-
},
|
|
365
|
-
status: 'ready',
|
|
366
|
-
source: 'product_shell_conversation_world_context',
|
|
367
|
-
runtimeWorldContext,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
const FEEDBACK_TOKEN_TO_SENTIMENT = Object.freeze({
|
|
2
|
-
'[[like]]': 'like',
|
|
3
|
-
'[[dislike]]': 'dislike',
|
|
4
|
-
});
|
|
5
|
-
|
|
6
|
-
const SENTIMENT_VALUES = Object.freeze(['like', 'dislike']);
|
|
7
|
-
|
|
8
|
-
function normalizeText(value, fallback = null) {
|
|
9
|
-
if (value == null) return fallback;
|
|
10
|
-
const normalized = String(value).trim();
|
|
11
|
-
return normalized || fallback;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function createConfigurationError() {
|
|
15
|
-
const error = new Error('conversation_feedback_store_unavailable');
|
|
16
|
-
error.code = 'conversation_feedback_store_unavailable';
|
|
17
|
-
error.status = 500;
|
|
18
|
-
return error;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function createInvalidConversationFeedbackError(fieldId, message = `${fieldId} is required`) {
|
|
22
|
-
const error = new Error(`invalid_conversation_feedback:${fieldId}`);
|
|
23
|
-
error.code = 'invalid_conversation_feedback';
|
|
24
|
-
error.status = 400;
|
|
25
|
-
error.responseBody = {
|
|
26
|
-
error: error.code,
|
|
27
|
-
message: 'conversation feedback request is invalid',
|
|
28
|
-
fieldErrors: [
|
|
29
|
-
{
|
|
30
|
-
fieldId,
|
|
31
|
-
message,
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
};
|
|
35
|
-
return error;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function normalizeSentiment(value, fallback = null) {
|
|
39
|
-
const normalized = normalizeText(value, fallback);
|
|
40
|
-
return SENTIMENT_VALUES.includes(normalized) ? normalized : fallback;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function resolveSentimentFromToken(token = null) {
|
|
44
|
-
const normalizedToken = normalizeText(token, null);
|
|
45
|
-
return normalizedToken ? FEEDBACK_TOKEN_TO_SENTIMENT[normalizedToken] || null : null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function parseConversationFeedbackTokens(text = '') {
|
|
49
|
-
if (typeof text !== 'string' || !text.trim()) {
|
|
50
|
-
return {
|
|
51
|
-
tokens: [],
|
|
52
|
-
sentiment: null,
|
|
53
|
-
conflict: false,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const matches = [...text.matchAll(/\[\[(like|dislike)\]\]/g)];
|
|
58
|
-
if (matches.length === 0) {
|
|
59
|
-
return {
|
|
60
|
-
tokens: [],
|
|
61
|
-
sentiment: null,
|
|
62
|
-
conflict: false,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const tokens = [...new Set(matches.map((match) => `[[${String(match[1] || '').trim().toLowerCase()}]]`))];
|
|
67
|
-
const sentiments = [...new Set(tokens.map((token) => resolveSentimentFromToken(token)).filter(Boolean))];
|
|
68
|
-
return {
|
|
69
|
-
tokens,
|
|
70
|
-
sentiment: sentiments.length === 1 ? sentiments[0] : null,
|
|
71
|
-
conflict: sentiments.length > 1,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function projectFeedbackMark(feedbackMark = {}) {
|
|
76
|
-
return {
|
|
77
|
-
feedbackMarkId: normalizeText(feedbackMark.feedbackMarkId, null),
|
|
78
|
-
conversationKey: normalizeText(feedbackMark.conversationKey, null),
|
|
79
|
-
worldId: normalizeText(feedbackMark.worldId, null),
|
|
80
|
-
giverAgentId: normalizeText(feedbackMark.giverAgentId, null),
|
|
81
|
-
receiverAgentId: normalizeText(feedbackMark.receiverAgentId, null),
|
|
82
|
-
sourceTurnId: normalizeText(feedbackMark.sourceTurnId, null),
|
|
83
|
-
sourceDeliveryId: normalizeText(feedbackMark.sourceDeliveryId, null),
|
|
84
|
-
token: normalizeText(feedbackMark.token, null),
|
|
85
|
-
sentiment: normalizeSentiment(feedbackMark.sentiment, null),
|
|
86
|
-
source: normalizeText(feedbackMark.source, 'reply_control_token'),
|
|
87
|
-
status: normalizeText(feedbackMark.status, 'active'),
|
|
88
|
-
createdAt: normalizeText(feedbackMark.createdAt, null),
|
|
89
|
-
updatedAt: normalizeText(feedbackMark.updatedAt, normalizeText(feedbackMark.createdAt, null)),
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function summarizeReceived(items = []) {
|
|
94
|
-
return {
|
|
95
|
-
likesReceived: items.filter((item) => item.sentiment === 'like').length,
|
|
96
|
-
dislikesReceived: items.filter((item) => item.sentiment === 'dislike').length,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function createConversationFeedbackService({ store } = {}) {
|
|
101
|
-
if (
|
|
102
|
-
!store
|
|
103
|
-
|| typeof store.createConversationFeedbackMark !== 'function'
|
|
104
|
-
|| typeof store.listConversationFeedbackMarks !== 'function'
|
|
105
|
-
|| typeof store.findConversationFeedbackMarkByConversationAndActors !== 'function'
|
|
106
|
-
) {
|
|
107
|
-
throw createConfigurationError();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
parseTokens(text = '') {
|
|
112
|
-
return parseConversationFeedbackTokens(text);
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
async recordFeedback({
|
|
116
|
-
conversationKey,
|
|
117
|
-
worldId = null,
|
|
118
|
-
giverAgentId,
|
|
119
|
-
receiverAgentId,
|
|
120
|
-
sourceTurnId = null,
|
|
121
|
-
sourceDeliveryId = null,
|
|
122
|
-
token = null,
|
|
123
|
-
sentiment = null,
|
|
124
|
-
} = {}) {
|
|
125
|
-
const normalizedConversationKey = normalizeText(conversationKey, null);
|
|
126
|
-
if (!normalizedConversationKey) {
|
|
127
|
-
throw createInvalidConversationFeedbackError('conversationKey');
|
|
128
|
-
}
|
|
129
|
-
const normalizedGiverAgentId = normalizeText(giverAgentId, null);
|
|
130
|
-
if (!normalizedGiverAgentId) {
|
|
131
|
-
throw createInvalidConversationFeedbackError('giverAgentId');
|
|
132
|
-
}
|
|
133
|
-
const normalizedReceiverAgentId = normalizeText(receiverAgentId, null);
|
|
134
|
-
if (!normalizedReceiverAgentId) {
|
|
135
|
-
throw createInvalidConversationFeedbackError('receiverAgentId');
|
|
136
|
-
}
|
|
137
|
-
const normalizedToken = normalizeText(token, null);
|
|
138
|
-
const normalizedSentiment = normalizeSentiment(sentiment, resolveSentimentFromToken(normalizedToken));
|
|
139
|
-
if (!normalizedSentiment) {
|
|
140
|
-
throw createInvalidConversationFeedbackError('sentiment', 'sentiment must be like or dislike');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const existing = store.findConversationFeedbackMarkByConversationAndActors({
|
|
144
|
-
conversationKey: normalizedConversationKey,
|
|
145
|
-
giverAgentId: normalizedGiverAgentId,
|
|
146
|
-
receiverAgentId: normalizedReceiverAgentId,
|
|
147
|
-
});
|
|
148
|
-
if (existing) {
|
|
149
|
-
return {
|
|
150
|
-
recorded: false,
|
|
151
|
-
deduped: true,
|
|
152
|
-
feedbackMark: projectFeedbackMark(existing),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const feedbackMark = await store.createConversationFeedbackMark({
|
|
157
|
-
conversationKey: normalizedConversationKey,
|
|
158
|
-
worldId: normalizeText(worldId, null),
|
|
159
|
-
giverAgentId: normalizedGiverAgentId,
|
|
160
|
-
receiverAgentId: normalizedReceiverAgentId,
|
|
161
|
-
sourceTurnId: normalizeText(sourceTurnId, null),
|
|
162
|
-
sourceDeliveryId: normalizeText(sourceDeliveryId, null),
|
|
163
|
-
token: normalizedToken || `[[${normalizedSentiment}]]`,
|
|
164
|
-
sentiment: normalizedSentiment,
|
|
165
|
-
source: 'reply_control_token',
|
|
166
|
-
status: 'active',
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
recorded: true,
|
|
171
|
-
deduped: false,
|
|
172
|
-
feedbackMark: projectFeedbackMark(feedbackMark),
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
|
|
176
|
-
listFeedbackMarks(filters = {}) {
|
|
177
|
-
return store.listConversationFeedbackMarks(filters).map((item) => projectFeedbackMark(item));
|
|
178
|
-
},
|
|
179
|
-
|
|
180
|
-
summarizeConversation({ conversationKey, viewerAgentId = null } = {}) {
|
|
181
|
-
const normalizedConversationKey = normalizeText(conversationKey, null);
|
|
182
|
-
const normalizedViewerAgentId = normalizeText(viewerAgentId, null);
|
|
183
|
-
const items = normalizedConversationKey
|
|
184
|
-
? this.listFeedbackMarks({ conversationKey: normalizedConversationKey, status: 'active' })
|
|
185
|
-
: [];
|
|
186
|
-
const viewerGave = normalizedViewerAgentId
|
|
187
|
-
? items.find((item) => item.giverAgentId === normalizedViewerAgentId)?.sentiment || null
|
|
188
|
-
: null;
|
|
189
|
-
const viewerReceived = normalizedViewerAgentId
|
|
190
|
-
? items.find((item) => item.receiverAgentId === normalizedViewerAgentId)?.sentiment || null
|
|
191
|
-
: null;
|
|
192
|
-
return {
|
|
193
|
-
likeCount: items.filter((item) => item.sentiment === 'like').length,
|
|
194
|
-
dislikeCount: items.filter((item) => item.sentiment === 'dislike').length,
|
|
195
|
-
viewerGave,
|
|
196
|
-
viewerReceived,
|
|
197
|
-
};
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
summarizeAgent({ agentId } = {}) {
|
|
201
|
-
const normalizedAgentId = normalizeText(agentId, null);
|
|
202
|
-
if (!normalizedAgentId) {
|
|
203
|
-
return {
|
|
204
|
-
totalLikesReceived: 0,
|
|
205
|
-
totalDislikesReceived: 0,
|
|
206
|
-
totalLikesGiven: 0,
|
|
207
|
-
totalDislikesGiven: 0,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
const received = this.listFeedbackMarks({
|
|
211
|
-
receiverAgentId: normalizedAgentId,
|
|
212
|
-
status: 'active',
|
|
213
|
-
});
|
|
214
|
-
const given = this.listFeedbackMarks({
|
|
215
|
-
giverAgentId: normalizedAgentId,
|
|
216
|
-
status: 'active',
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
return {
|
|
220
|
-
totalLikesReceived: received.filter((item) => item.sentiment === 'like').length,
|
|
221
|
-
totalDislikesReceived: received.filter((item) => item.sentiment === 'dislike').length,
|
|
222
|
-
totalLikesGiven: given.filter((item) => item.sentiment === 'like').length,
|
|
223
|
-
totalDislikesGiven: given.filter((item) => item.sentiment === 'dislike').length,
|
|
224
|
-
};
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
summarizeWorldAgent({ worldId, agentId } = {}) {
|
|
228
|
-
const normalizedWorldId = normalizeText(worldId, null);
|
|
229
|
-
const normalizedAgentId = normalizeText(agentId, null);
|
|
230
|
-
if (!normalizedWorldId || !normalizedAgentId) {
|
|
231
|
-
return {
|
|
232
|
-
likesReceived: 0,
|
|
233
|
-
dislikesReceived: 0,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
return summarizeReceived(this.listFeedbackMarks({
|
|
237
|
-
worldId: normalizedWorldId,
|
|
238
|
-
receiverAgentId: normalizedAgentId,
|
|
239
|
-
status: 'active',
|
|
240
|
-
}));
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
summarizeWorld({ worldId } = {}) {
|
|
244
|
-
const normalizedWorldId = normalizeText(worldId, null);
|
|
245
|
-
if (!normalizedWorldId) {
|
|
246
|
-
return {
|
|
247
|
-
totalLikes: 0,
|
|
248
|
-
totalDislikes: 0,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
const items = this.listFeedbackMarks({
|
|
252
|
-
worldId: normalizedWorldId,
|
|
253
|
-
status: 'active',
|
|
254
|
-
});
|
|
255
|
-
return {
|
|
256
|
-
totalLikes: items.filter((item) => item.sentiment === 'like').length,
|
|
257
|
-
totalDislikes: items.filter((item) => item.sentiment === 'dislike').length,
|
|
258
|
-
};
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
}
|