@xfxstudio/claworld 0.2.12 → 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.
Files changed (62) hide show
  1. package/README.md +45 -19
  2. package/index.js +0 -1
  3. package/openclaw.plugin.json +1 -1
  4. package/package.json +1 -5
  5. package/skills/claworld-help/SKILL.md +84 -91
  6. package/skills/claworld-join-and-chat/SKILL.md +9 -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 +8 -253
  10. package/src/openclaw/plugin/managed-config.js +1 -7
  11. package/src/openclaw/plugin/onboarding.js +128 -103
  12. package/src/openclaw/plugin/register.js +183 -232
  13. package/src/openclaw/plugin/relay-client.js +8 -5
  14. package/src/openclaw/runtime/product-shell-helper.js +11 -364
  15. package/src/openclaw/runtime/tool-contracts.js +0 -182
  16. package/src/openclaw/runtime/tool-inventory.js +4 -27
  17. package/bin/claworld.mjs +0 -9
  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/cli.js +0 -406
  22. package/src/openclaw/installer/constants.js +0 -14
  23. package/src/openclaw/installer/core.js +0 -2122
  24. package/src/openclaw/installer/doctor.js +0 -876
  25. package/src/openclaw/installer/workspace-contract.js +0 -427
  26. package/src/product-shell/agent-cards/card-routes.js +0 -64
  27. package/src/product-shell/agent-cards/card-service.js +0 -287
  28. package/src/product-shell/agent-cards/spec-builder.js +0 -167
  29. package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
  30. package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
  31. package/src/product-shell/agent-cards/svg-renderer.js +0 -325
  32. package/src/product-shell/agent-cards/template-registry.js +0 -131
  33. package/src/product-shell/catalog/default-world-catalog.js +0 -38
  34. package/src/product-shell/contracts/candidate-feed.js +0 -393
  35. package/src/product-shell/contracts/world-manifest.js +0 -369
  36. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
  37. package/src/product-shell/feedback/feedback-contract.js +0 -13
  38. package/src/product-shell/feedback/feedback-routes.js +0 -98
  39. package/src/product-shell/feedback/feedback-service.js +0 -252
  40. package/src/product-shell/index.js +0 -212
  41. package/src/product-shell/matching/matchmaking-service.js +0 -395
  42. package/src/product-shell/membership/membership-service.js +0 -284
  43. package/src/product-shell/onboarding/onboarding-routes.js +0 -37
  44. package/src/product-shell/onboarding/onboarding-service.js +0 -220
  45. package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
  46. package/src/product-shell/profile/profile-service.js +0 -142
  47. package/src/product-shell/profile/public-identity-routes.js +0 -160
  48. package/src/product-shell/profile/public-identity-service.js +0 -192
  49. package/src/product-shell/search/search-service.js +0 -393
  50. package/src/product-shell/social/chat-request-approval-policy.js +0 -332
  51. package/src/product-shell/social/chat-request-routes.js +0 -130
  52. package/src/product-shell/social/chat-request-service.js +0 -723
  53. package/src/product-shell/social/friend-routes.js +0 -82
  54. package/src/product-shell/social/friend-service.js +0 -557
  55. package/src/product-shell/social/social-routes.js +0 -21
  56. package/src/product-shell/social/social-service.js +0 -136
  57. package/src/product-shell/worlds/world-admin-service.js +0 -486
  58. package/src/product-shell/worlds/world-authorization.js +0 -136
  59. package/src/product-shell/worlds/world-broadcast-service.js +0 -296
  60. package/src/product-shell/worlds/world-routes.js +0 -403
  61. package/src/product-shell/worlds/world-service.js +0 -89
  62. 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
- }
@@ -1,13 +0,0 @@
1
- export const FEEDBACK_CATEGORY_VALUES = Object.freeze([
2
- 'experience_issue',
3
- 'usage_issue',
4
- 'bug_report',
5
- 'feature_request',
6
- ]);
7
-
8
- export const FEEDBACK_IMPACT_VALUES = Object.freeze([
9
- 'low',
10
- 'medium',
11
- 'high',
12
- 'blocker',
13
- ]);