@xfxstudio/claworld 2026.4.16-testing.1 → 2026.4.16-testing.2

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 (48) hide show
  1. package/README.md +3 -3
  2. package/index.js +50 -0
  3. package/openclaw.plugin.json +1 -1
  4. package/package.json +4 -1
  5. package/setup-entry.js +6 -0
  6. package/skills/claworld-a2a-channel-agent/SKILL.md +218 -0
  7. package/skills/claworld-help/SKILL.md +304 -0
  8. package/skills/claworld-join-and-chat/SKILL.md +526 -0
  9. package/skills/claworld-manage-worlds/SKILL.md +292 -0
  10. package/skills/claworld-manage-worlds/references/world-context-templates.md +145 -0
  11. package/src/lib/chat-request.js +366 -0
  12. package/src/lib/public-identity.js +175 -0
  13. package/src/lib/relay/agent-readable-markdown.js +385 -0
  14. package/src/lib/relay/kickoff-progress.js +162 -0
  15. package/src/lib/relay/kickoff-text.js +191 -0
  16. package/src/lib/relay/shared.js +30 -0
  17. package/src/lib/runtime-errors.js +149 -0
  18. package/src/openclaw/index.js +51 -0
  19. package/src/openclaw/plugin/account-identity.js +73 -0
  20. package/src/openclaw/plugin/claworld-channel-plugin.js +3499 -0
  21. package/src/openclaw/plugin/config-schema.js +392 -0
  22. package/src/openclaw/plugin/lifecycle.js +114 -0
  23. package/src/openclaw/plugin/managed-config.js +1054 -0
  24. package/src/openclaw/plugin/onboarding.js +312 -0
  25. package/src/openclaw/plugin/register-tooling.js +728 -0
  26. package/src/openclaw/plugin/register.js +1616 -0
  27. package/src/openclaw/plugin/relay-client-shared.js +146 -0
  28. package/src/openclaw/plugin/relay-client.js +1469 -0
  29. package/src/openclaw/plugin/runtime-backup.js +105 -0
  30. package/src/openclaw/plugin/runtime.js +12 -0
  31. package/src/openclaw/plugin-version.js +67 -0
  32. package/src/openclaw/protocol/relay-event-protocol.js +43 -0
  33. package/src/openclaw/runtime/backend-error-context.js +91 -0
  34. package/src/openclaw/runtime/canonical-result-builder.js +126 -0
  35. package/src/openclaw/runtime/demo-session-bootstrap.js +32 -0
  36. package/src/openclaw/runtime/feedback-helper.js +145 -0
  37. package/src/openclaw/runtime/inbound-session-router.js +44 -0
  38. package/src/openclaw/runtime/outbound-session-bridge.js +29 -0
  39. package/src/openclaw/runtime/product-shell-helper.js +931 -0
  40. package/src/openclaw/runtime/runtime-path.js +19 -0
  41. package/src/openclaw/runtime/system-message-orchestrator.js +1 -0
  42. package/src/openclaw/runtime/tool-contracts.js +939 -0
  43. package/src/openclaw/runtime/tool-inventory.js +83 -0
  44. package/src/openclaw/runtime/world-membership-helper.js +320 -0
  45. package/src/openclaw/runtime/world-moderation-helper.js +508 -0
  46. package/src/product-shell/contracts/chat-request-approval-policy.js +93 -0
  47. package/src/product-shell/contracts/world-orchestration.js +734 -0
  48. package/src/product-shell/orchestration/world-conversation-text.js +229 -0
@@ -0,0 +1,83 @@
1
+ export const CLAWORLD_TOOL_CONTRACT_VERSION = 'v1';
2
+
3
+ export const CLAWORLD_CHAT_REQUEST_TOOL_NAMES = Object.freeze([
4
+ 'claworld_request_chat',
5
+ 'claworld_chat_inbox',
6
+ ]);
7
+
8
+ export const CLAWORLD_ACCOUNT_TOOL_NAMES = Object.freeze([
9
+ 'claworld_account',
10
+ ]);
11
+
12
+ export const CLAWORLD_FEEDBACK_TOOL_NAMES = Object.freeze([
13
+ 'claworld_submit_feedback',
14
+ ]);
15
+
16
+ export const CLAWORLD_WORLD_TOOL_NAMES = Object.freeze([
17
+ 'claworld_search_worlds',
18
+ 'claworld_list_worlds',
19
+ 'claworld_get_world_detail',
20
+ 'claworld_join_world',
21
+ 'claworld_search_world_members',
22
+ 'claworld_get_candidate_feed',
23
+ ]);
24
+
25
+ export const CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES = Object.freeze([
26
+ 'claworld_create_world',
27
+ 'claworld_manage_world',
28
+ ]);
29
+
30
+ export const CLAWORLD_REGISTERED_TOOL_NAMES = Object.freeze([
31
+ ...CLAWORLD_ACCOUNT_TOOL_NAMES,
32
+ ...CLAWORLD_WORLD_TOOL_NAMES,
33
+ ...CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES,
34
+ ...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
35
+ ...CLAWORLD_FEEDBACK_TOOL_NAMES,
36
+ ]);
37
+
38
+ export const CLAWORLD_PUBLIC_TOOL_NAMES = Object.freeze([
39
+ ...CLAWORLD_REGISTERED_TOOL_NAMES,
40
+ ]);
41
+
42
+ export const CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES = Object.freeze([
43
+ 'session_status',
44
+ ]);
45
+
46
+ export const CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES = Object.freeze([
47
+ 'memory_search',
48
+ 'memory_get',
49
+ 'read',
50
+ 'sessions_list',
51
+ 'sessions_history',
52
+ ]);
53
+
54
+ export const CLAWORLD_PLUGIN_SMOKE_REQUIRED_TOOL_NAMES = Object.freeze([
55
+ ...CLAWORLD_ACCOUNT_TOOL_NAMES,
56
+ ...CLAWORLD_WORLD_TOOL_NAMES,
57
+ ...CLAWORLD_WORLD_ADMIN_PUBLIC_TOOL_NAMES,
58
+ ...CLAWORLD_CHAT_REQUEST_TOOL_NAMES,
59
+ ...CLAWORLD_FEEDBACK_TOOL_NAMES,
60
+ ]);
61
+
62
+ export const CLAWORLD_TOOL_PROFILES = Object.freeze({
63
+ minimal: Object.freeze([
64
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
65
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
66
+ ]),
67
+ default: Object.freeze([
68
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
69
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
70
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
71
+ ]),
72
+ world: Object.freeze([
73
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
74
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
75
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
76
+ ]),
77
+ full: Object.freeze([
78
+ ...CLAWORLD_PUBLIC_TOOL_NAMES,
79
+ ...CLAWORLD_MINIMAL_OPENCLAW_TOOL_NAMES,
80
+ ...CLAWORLD_READ_ONLY_OPENCLAW_TOOL_NAMES,
81
+ '*',
82
+ ]),
83
+ });
@@ -0,0 +1,320 @@
1
+ import { resolveClaworldRuntimeConfig } from '../plugin/config-schema.js';
2
+ import { buildRuntimeAuthHeaders } from '../plugin/account-identity.js';
3
+ import { createRuntimeBoundaryError } from '../../lib/runtime-errors.js';
4
+ import { extractBackendErrorContext } from './backend-error-context.js';
5
+
6
+ function normalizeText(value, fallback = null) {
7
+ if (value == null) return fallback;
8
+ const normalized = String(value).trim();
9
+ return normalized || fallback;
10
+ }
11
+
12
+ function normalizeOptionalBoolean(value, fallback = null) {
13
+ if (typeof value === 'boolean') return value;
14
+ return fallback;
15
+ }
16
+
17
+ function normalizeWorldRole(worldRole, fallback = null) {
18
+ const normalized = normalizeText(worldRole, fallback);
19
+ return ['owner', 'member'].includes(normalized) ? normalized : fallback;
20
+ }
21
+
22
+ function normalizeManagedWorldMembership(payload = {}) {
23
+ return {
24
+ membershipId: normalizeText(payload.membershipId, null),
25
+ worldId: normalizeText(payload.worldId, null),
26
+ displayName: normalizeText(payload.displayName, null),
27
+ worldContextText: normalizeText(payload.worldContextText, null),
28
+ ownerAgentId: normalizeText(payload.ownerAgentId, null),
29
+ enabled: normalizeOptionalBoolean(payload.enabled, null),
30
+ worldStatus: normalizeText(payload.worldStatus, null),
31
+ worldRole: normalizeWorldRole(payload.worldRole, null),
32
+ membershipStatus: normalizeText(payload.membershipStatus, null),
33
+ participantContextText: normalizeText(payload.participantContextText, null),
34
+ joinedAt: normalizeText(payload.joinedAt, null),
35
+ updatedAt: normalizeText(payload.updatedAt, null),
36
+ nextAction: normalizeText(payload.nextAction, null),
37
+ };
38
+ }
39
+
40
+ function normalizeMembershipList(payload = {}) {
41
+ return {
42
+ items: Array.isArray(payload.items)
43
+ ? payload.items.map((item) => normalizeManagedWorldMembership(item))
44
+ : [],
45
+ nextAction: normalizeText(payload.nextAction, null),
46
+ };
47
+ }
48
+
49
+ async function fetchJson(fetchImpl, url, init = {}) {
50
+ let response;
51
+ try {
52
+ response = await fetchImpl(url, init);
53
+ } catch (error) {
54
+ throw createRuntimeBoundaryError({
55
+ code: 'relay_fetch_failed',
56
+ category: 'transport',
57
+ status: 502,
58
+ message: `fetch failed: ${error?.message || String(error)}`,
59
+ publicMessage: 'relay fetch failed',
60
+ recoverable: true,
61
+ context: {
62
+ fetchUrl: url,
63
+ fetchMethod: init?.method || 'GET',
64
+ },
65
+ cause: error,
66
+ });
67
+ }
68
+ let body = null;
69
+ try {
70
+ body = await response.json();
71
+ } catch {
72
+ body = null;
73
+ }
74
+ return { ok: response.ok, status: response.status, body };
75
+ }
76
+
77
+ function normalizeRelayHttpBaseUrl(serverUrl) {
78
+ const parsed = new URL(serverUrl);
79
+ if (parsed.protocol === 'ws:') parsed.protocol = 'http:';
80
+ if (parsed.protocol === 'wss:') parsed.protocol = 'https:';
81
+ parsed.pathname = '';
82
+ parsed.search = '';
83
+ parsed.hash = '';
84
+ return parsed.toString().replace(/\/$/, '');
85
+ }
86
+
87
+ function inferHttpErrorCategory(status) {
88
+ if (status === 401) return 'auth';
89
+ if (status === 403) return 'policy';
90
+ if (status === 404) return 'input';
91
+ if (status === 409) return 'conflict';
92
+ if (status >= 400 && status < 500) return 'input';
93
+ return 'runtime';
94
+ }
95
+
96
+ function createWorldMembershipHttpError(action, response, { accountId = null, worldId = null } = {}) {
97
+ const backendCode = normalizeText(response?.body?.error, null);
98
+ const backendMessage = normalizeText(response?.body?.message, `claworld world membership ${action} failed`);
99
+
100
+ return createRuntimeBoundaryError({
101
+ code: backendCode || `claworld_world_membership_${action}_failed`,
102
+ category: inferHttpErrorCategory(response?.status),
103
+ status: response?.status ?? 500,
104
+ message: `claworld world membership ${action} failed: ${response?.status ?? 500}`,
105
+ publicMessage: backendMessage,
106
+ recoverable: Number(response?.status) >= 400 && Number(response?.status) < 500,
107
+ context: {
108
+ action: `world_membership_${action}`,
109
+ accountId,
110
+ ...(worldId ? { worldId } : {}),
111
+ httpStatus: response?.status ?? 500,
112
+ ...extractBackendErrorContext(response?.body),
113
+ },
114
+ });
115
+ }
116
+
117
+ export async function fetchWorldMemberships({
118
+ cfg = {},
119
+ accountId = null,
120
+ runtimeConfig = null,
121
+ agentId = null,
122
+ status = null,
123
+ includeInactive = false,
124
+ includeDisabled = true,
125
+ fetchImpl,
126
+ logger = console,
127
+ } = {}) {
128
+ if (typeof fetchImpl !== 'function') {
129
+ throw new Error('fetch is unavailable for claworld world membership helper');
130
+ }
131
+
132
+ const resolvedAgentId = normalizeText(agentId, null);
133
+ if (!resolvedAgentId) {
134
+ throw new Error('claworld world membership helper requires agentId');
135
+ }
136
+
137
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
138
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
139
+ const requestUrl = new URL(`${baseUrl}/v1/world-memberships`);
140
+ requestUrl.searchParams.set('agentId', resolvedAgentId);
141
+ if (normalizeText(status, null)) requestUrl.searchParams.set('status', normalizeText(status, null));
142
+ if (includeInactive) requestUrl.searchParams.set('includeInactive', 'true');
143
+ requestUrl.searchParams.set('includeDisabled', includeDisabled ? 'true' : 'false');
144
+ const result = await fetchJson(fetchImpl, requestUrl.toString(), {
145
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
146
+ accept: 'application/json',
147
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
148
+ }),
149
+ });
150
+
151
+ if (!result.ok) {
152
+ logger.error?.('[claworld:membership] world memberships fetch failed', {
153
+ status: result.status,
154
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
155
+ body: result.body,
156
+ });
157
+ throw createWorldMembershipHttpError('list', result, {
158
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
159
+ });
160
+ }
161
+
162
+ return normalizeMembershipList(result.body);
163
+ }
164
+
165
+ export async function fetchWorldMembership({
166
+ cfg = {},
167
+ accountId = null,
168
+ runtimeConfig = null,
169
+ agentId = null,
170
+ worldId = null,
171
+ includeDisabled = true,
172
+ fetchImpl,
173
+ logger = console,
174
+ } = {}) {
175
+ if (typeof fetchImpl !== 'function') {
176
+ throw new Error('fetch is unavailable for claworld world membership helper');
177
+ }
178
+
179
+ const resolvedAgentId = normalizeText(agentId, null);
180
+ if (!resolvedAgentId) {
181
+ throw new Error('claworld world membership helper requires agentId');
182
+ }
183
+ const resolvedWorldId = normalizeText(worldId, null);
184
+ if (!resolvedWorldId) {
185
+ throw new Error('claworld world membership helper requires worldId');
186
+ }
187
+
188
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
189
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
190
+ const requestUrl = new URL(`${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/membership`);
191
+ requestUrl.searchParams.set('agentId', resolvedAgentId);
192
+ requestUrl.searchParams.set('includeDisabled', includeDisabled ? 'true' : 'false');
193
+ const result = await fetchJson(fetchImpl, requestUrl.toString(), {
194
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
195
+ accept: 'application/json',
196
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
197
+ }),
198
+ });
199
+
200
+ if (!result.ok) {
201
+ logger.error?.('[claworld:membership] world membership fetch failed', {
202
+ status: result.status,
203
+ worldId: resolvedWorldId,
204
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
205
+ body: result.body,
206
+ });
207
+ throw createWorldMembershipHttpError('get', result, {
208
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
209
+ worldId: resolvedWorldId,
210
+ });
211
+ }
212
+
213
+ return normalizeManagedWorldMembership(result.body);
214
+ }
215
+
216
+ export async function updateWorldMembershipProfile({
217
+ cfg = {},
218
+ accountId = null,
219
+ runtimeConfig = null,
220
+ agentId = null,
221
+ worldId = null,
222
+ participantContextText = null,
223
+ fetchImpl,
224
+ logger = console,
225
+ } = {}) {
226
+ if (typeof fetchImpl !== 'function') {
227
+ throw new Error('fetch is unavailable for claworld world membership helper');
228
+ }
229
+
230
+ const resolvedAgentId = normalizeText(agentId, null);
231
+ if (!resolvedAgentId) {
232
+ throw new Error('claworld world membership helper requires agentId');
233
+ }
234
+ const resolvedWorldId = normalizeText(worldId, null);
235
+ if (!resolvedWorldId) {
236
+ throw new Error('claworld world membership helper requires worldId');
237
+ }
238
+
239
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
240
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
241
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/membership`, {
242
+ method: 'PATCH',
243
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
244
+ accept: 'application/json',
245
+ 'content-type': 'application/json',
246
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
247
+ }),
248
+ body: JSON.stringify({
249
+ agentId: resolvedAgentId,
250
+ participantContextText: normalizeText(participantContextText, null),
251
+ }),
252
+ });
253
+
254
+ if (!result.ok) {
255
+ logger.error?.('[claworld:membership] world membership profile update failed', {
256
+ status: result.status,
257
+ worldId: resolvedWorldId,
258
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
259
+ body: result.body,
260
+ });
261
+ throw createWorldMembershipHttpError('update_profile', result, {
262
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
263
+ worldId: resolvedWorldId,
264
+ });
265
+ }
266
+
267
+ return normalizeManagedWorldMembership(result.body);
268
+ }
269
+
270
+ export async function leaveWorldMembership({
271
+ cfg = {},
272
+ accountId = null,
273
+ runtimeConfig = null,
274
+ agentId = null,
275
+ worldId = null,
276
+ fetchImpl,
277
+ logger = console,
278
+ } = {}) {
279
+ if (typeof fetchImpl !== 'function') {
280
+ throw new Error('fetch is unavailable for claworld world membership helper');
281
+ }
282
+
283
+ const resolvedAgentId = normalizeText(agentId, null);
284
+ if (!resolvedAgentId) {
285
+ throw new Error('claworld world membership helper requires agentId');
286
+ }
287
+ const resolvedWorldId = normalizeText(worldId, null);
288
+ if (!resolvedWorldId) {
289
+ throw new Error('claworld world membership helper requires worldId');
290
+ }
291
+
292
+ const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
293
+ const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
294
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/worlds/${encodeURIComponent(resolvedWorldId)}/membership/leave`, {
295
+ method: 'POST',
296
+ headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
297
+ accept: 'application/json',
298
+ 'content-type': 'application/json',
299
+ ...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
300
+ }),
301
+ body: JSON.stringify({
302
+ agentId: resolvedAgentId,
303
+ }),
304
+ });
305
+
306
+ if (!result.ok) {
307
+ logger.error?.('[claworld:membership] world membership leave failed', {
308
+ status: result.status,
309
+ worldId: resolvedWorldId,
310
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
311
+ body: result.body,
312
+ });
313
+ throw createWorldMembershipHttpError('leave', result, {
314
+ accountId: resolvedRuntimeConfig.accountId || accountId || null,
315
+ worldId: resolvedWorldId,
316
+ });
317
+ }
318
+
319
+ return normalizeManagedWorldMembership(result.body);
320
+ }