@xfxstudio/claworld 2026.6.30-testing.1 → 2026.7.1-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.
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "name": "Claworld Persona Relay",
19
19
  "description": "Claworld relay world channel plugin for OpenClaw.",
20
- "version": "2026.6.30-testing.1",
20
+ "version": "2026.7.1-testing.2",
21
21
  "configSchema": {
22
22
  "type": "object",
23
23
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfxstudio/claworld",
3
- "version": "2026.6.30-testing.1",
3
+ "version": "2026.7.1-testing.2",
4
4
  "description": "Claworld channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -99,6 +99,24 @@ export function normalizeChatRequestOpeningPayload(input = null) {
99
99
  return Object.keys(payload).length > 0 ? payload : null;
100
100
  }
101
101
 
102
+ function normalizeKickoffBriefInput(kickoffBrief = null) {
103
+ if (kickoffBrief && typeof kickoffBrief === 'object' && !Array.isArray(kickoffBrief)) {
104
+ return kickoffBrief;
105
+ }
106
+ const text = normalizeText(kickoffBrief, null);
107
+ return text ? { text } : null;
108
+ }
109
+
110
+ function resolveKickoffBriefOpeningMessage(kickoffBrief = null, fallback = null) {
111
+ if (!kickoffBrief || typeof kickoffBrief !== 'object' || Array.isArray(kickoffBrief)) {
112
+ return normalizeText(fallback, null);
113
+ }
114
+ return normalizeText(
115
+ kickoffBrief.text,
116
+ normalizeText(kickoffBrief.openingMessage, normalizeText(kickoffBrief.message, normalizeText(fallback, null))),
117
+ );
118
+ }
119
+
102
120
  export function resolveChatRequestOpeningMessage({
103
121
  openingMessage = null,
104
122
  openingPayload = null,
@@ -119,12 +137,8 @@ function resolveKickoffBriefSource({
119
137
  const normalizedContext = requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
120
138
  ? requestContext
121
139
  : {};
122
- const explicitKickoffBrief = kickoffBrief && typeof kickoffBrief === 'object' && !Array.isArray(kickoffBrief)
123
- ? kickoffBrief
124
- : null;
125
- const contextKickoffBrief = normalizedContext.kickoffBrief && typeof normalizedContext.kickoffBrief === 'object' && !Array.isArray(normalizedContext.kickoffBrief)
126
- ? normalizedContext.kickoffBrief
127
- : null;
140
+ const explicitKickoffBrief = normalizeKickoffBriefInput(kickoffBrief);
141
+ const contextKickoffBrief = normalizeKickoffBriefInput(normalizedContext.kickoffBrief);
128
142
  const fallbackSource = normalizeText(source, null) === 'world_broadcast'
129
143
  ? 'world_broadcast_brief'
130
144
  : 'chat_request_brief';
@@ -150,12 +164,8 @@ function resolveChatRequestKickoffBrief({
150
164
  const normalizedContext = requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
151
165
  ? requestContext
152
166
  : {};
153
- const explicitKickoffBrief = kickoffBrief && typeof kickoffBrief === 'object' && !Array.isArray(kickoffBrief)
154
- ? kickoffBrief
155
- : null;
156
- const contextKickoffBrief = normalizedContext.kickoffBrief && typeof normalizedContext.kickoffBrief === 'object' && !Array.isArray(normalizedContext.kickoffBrief)
157
- ? normalizedContext.kickoffBrief
158
- : null;
167
+ const explicitKickoffBrief = normalizeKickoffBriefInput(kickoffBrief);
168
+ const contextKickoffBrief = normalizeKickoffBriefInput(normalizedContext.kickoffBrief);
159
169
  const normalizedOpeningPayload = normalizeChatRequestOpeningPayload(
160
170
  explicitKickoffBrief?.payload
161
171
  ?? contextKickoffBrief?.payload
@@ -163,10 +173,10 @@ function resolveChatRequestKickoffBrief({
163
173
  ?? normalizedContext.openingPayload,
164
174
  );
165
175
  const normalizedOpeningMessage = resolveChatRequestOpeningMessage({
166
- openingMessage:
167
- explicitKickoffBrief?.text
168
- ?? contextKickoffBrief?.text
169
- ?? openingMessage,
176
+ openingMessage: resolveKickoffBriefOpeningMessage(
177
+ explicitKickoffBrief,
178
+ resolveKickoffBriefOpeningMessage(contextKickoffBrief, openingMessage),
179
+ ),
170
180
  openingPayload: normalizedOpeningPayload,
171
181
  requestContext: normalizedContext,
172
182
  });
@@ -271,6 +271,46 @@ function isClaworldPlainObject(value) {
271
271
  return value && typeof value === 'object' && !Array.isArray(value);
272
272
  }
273
273
 
274
+ function resolveClaworldOpeningMessage({
275
+ openingMessage = null,
276
+ message = null,
277
+ text = null,
278
+ kickoffBrief = null,
279
+ openingPayload = null,
280
+ } = {}) {
281
+ const brief = isClaworldPlainObject(kickoffBrief) ? kickoffBrief : null;
282
+ return normalizeClaworldText(
283
+ openingMessage,
284
+ normalizeClaworldText(
285
+ message,
286
+ normalizeClaworldText(
287
+ text,
288
+ normalizeClaworldText(
289
+ typeof kickoffBrief === 'string' ? kickoffBrief : null,
290
+ normalizeClaworldText(
291
+ brief?.text,
292
+ normalizeClaworldText(
293
+ brief?.openingMessage,
294
+ normalizeClaworldText(brief?.message, normalizeClaworldText(openingPayload?.text, null)),
295
+ ),
296
+ ),
297
+ ),
298
+ ),
299
+ ),
300
+ );
301
+ }
302
+
303
+ function normalizeClaworldKickoffBriefInput(kickoffBrief = null, openingMessage = null) {
304
+ if (isClaworldPlainObject(kickoffBrief)) {
305
+ return {
306
+ ...kickoffBrief,
307
+ ...(!resolveClaworldOpeningMessage({ kickoffBrief }) && openingMessage ? { text: openingMessage } : {}),
308
+ };
309
+ }
310
+ const text = normalizeClaworldText(kickoffBrief, null);
311
+ return text ? { text } : null;
312
+ }
313
+
274
314
  function resolveNormalizedText(value, fallback = null) {
275
315
  return normalizeClaworldText(value, fallback);
276
316
  }
@@ -894,6 +934,10 @@ async function createChatRequest({
894
934
  displayName = null,
895
935
  agentCode = null,
896
936
  openingMessage = null,
937
+ message = null,
938
+ text = null,
939
+ kickoffBrief = null,
940
+ openingPayload = null,
897
941
  worldId = null,
898
942
  requestContext = null,
899
943
  fetchImpl,
@@ -912,7 +956,15 @@ async function createChatRequest({
912
956
  });
913
957
  }
914
958
  const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
915
- const normalizedOpeningMessage = normalizeClaworldText(openingMessage, null);
959
+ const normalizedOpeningPayload = isClaworldPlainObject(openingPayload) ? openingPayload : null;
960
+ const normalizedOpeningMessage = resolveClaworldOpeningMessage({
961
+ openingMessage,
962
+ message,
963
+ text,
964
+ kickoffBrief,
965
+ openingPayload: normalizedOpeningPayload,
966
+ });
967
+ const normalizedKickoffBrief = normalizeClaworldKickoffBriefInput(kickoffBrief, normalizedOpeningMessage);
916
968
  if (!normalizedOpeningMessage) {
917
969
  const message = 'openingMessage is required for chat request kickoff';
918
970
  throw createRuntimeBoundaryError({
@@ -951,6 +1003,8 @@ async function createChatRequest({
951
1003
  displayName: normalizedDisplayName,
952
1004
  agentCode: normalizedAgentCode,
953
1005
  openingMessage: normalizedOpeningMessage,
1006
+ ...(normalizedKickoffBrief ? { kickoffBrief: normalizedKickoffBrief } : {}),
1007
+ ...(normalizedOpeningPayload ? { openingPayload: normalizedOpeningPayload } : {}),
954
1008
  ...(normalizeClaworldText(worldId, null) ? { worldId: normalizeClaworldText(worldId, null) } : {}),
955
1009
  ...(requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
956
1010
  ? { requestContext }
@@ -4553,6 +4607,10 @@ async function generateRuntimeProfileCard(context = {}) {
4553
4607
  displayName: context.displayName || null,
4554
4608
  agentCode: context.agentCode || null,
4555
4609
  openingMessage: context.openingMessage || context.message || context.text || null,
4610
+ message: context.message || null,
4611
+ text: context.text || null,
4612
+ kickoffBrief: context.kickoffBrief || null,
4613
+ openingPayload: context.openingPayload || null,
4556
4614
  worldId: context.worldId || null,
4557
4615
  requestContext,
4558
4616
  fetchImpl,
@@ -201,6 +201,28 @@ function hasExplicitAction(params = {}) {
201
201
  return Object.prototype.hasOwnProperty.call(params, 'action') && normalizeText(params.action, null) != null;
202
202
  }
203
203
 
204
+ function resolveConversationOpeningMessage(params = {}) {
205
+ const kickoffBrief = params?.kickoffBrief && typeof params.kickoffBrief === 'object' && !Array.isArray(params.kickoffBrief)
206
+ ? params.kickoffBrief
207
+ : null;
208
+ return normalizeText(
209
+ params?.openingMessage,
210
+ normalizeText(
211
+ params?.message,
212
+ normalizeText(
213
+ params?.text,
214
+ normalizeText(
215
+ typeof params?.kickoffBrief === 'string' ? params.kickoffBrief : null,
216
+ normalizeText(
217
+ kickoffBrief?.text,
218
+ normalizeText(kickoffBrief?.openingMessage, normalizeText(kickoffBrief?.message, normalizeText(params?.openingPayload?.text, null))),
219
+ ),
220
+ ),
221
+ ),
222
+ ),
223
+ );
224
+ }
225
+
204
226
  function normalizeTerminalAccountAction(params = {}) {
205
227
  if (hasExplicitAction(params)) {
206
228
  const explicitAction = normalizeText(params.action, null);
@@ -1069,6 +1091,16 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1069
1091
  displayName: stringParam({ description: 'Target public display name for request.', minLength: 1 }),
1070
1092
  agentCode: stringParam({ description: 'Target public agent code for request.', minLength: 1 }),
1071
1093
  openingMessage: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
1094
+ message: stringParam({ description: 'Alias for openingMessage on action=request.', minLength: 1 }),
1095
+ text: stringParam({ description: 'Alias for openingMessage on action=request.', minLength: 1 }),
1096
+ kickoffBrief: objectParam({
1097
+ description: 'Structured request kickoff brief. text/openingMessage/message are accepted as opener aliases.',
1098
+ properties: {
1099
+ text: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
1100
+ openingMessage: stringParam({ description: 'Alias for kickoff brief text.', minLength: 1 }),
1101
+ message: stringParam({ description: 'Alias for kickoff brief text.', minLength: 1 }),
1102
+ },
1103
+ }),
1072
1104
  worldId: worldIdProperty,
1073
1105
  direction: stringParam({
1074
1106
  description: 'Top-level alias for filters.direction on action=list_related/get_state.',
@@ -1096,11 +1128,25 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1096
1128
  async execute(toolCallId, params = {}) {
1097
1129
  const action = normalizeTerminalConversationAction(params.action, 'list_related', { throwOnInvalid: true });
1098
1130
  if (action === 'request') {
1099
- const result = await requireTerminalTool(internalTools, 'claworld_request_chat').execute(toolCallId, {
1100
- ...params,
1101
- action: 'request_chat',
1131
+ const context = await resolveToolContext(api, plugin, params, {
1132
+ requiredPublicIdentityCapability: 'request chat',
1133
+ });
1134
+ const payload = await plugin.helpers.social.requestChat({
1135
+ ...context,
1136
+ displayName: params.displayName,
1137
+ agentCode: params.agentCode,
1138
+ openingMessage: resolveConversationOpeningMessage(params),
1139
+ message: params.message || null,
1140
+ text: params.text || null,
1141
+ kickoffBrief: params.kickoffBrief || null,
1142
+ openingPayload: params.openingPayload || null,
1143
+ worldId: params.worldId || null,
1144
+ });
1145
+ return buildToolResult({
1146
+ ...projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }),
1147
+ tool: manageConversationsTool,
1148
+ action,
1102
1149
  });
1103
- return rewriteToolResultName(result, manageConversationsTool, action);
1104
1150
  }
1105
1151
  if (action === 'list_related' || action === 'get_state') {
1106
1152
  const filters = normalizeManageConversationInboxQuery(params, action);
@@ -1717,93 +1763,6 @@ function buildRegisteredTools(api, plugin) {
1717
1763
  }));
1718
1764
  },
1719
1765
  },
1720
- {
1721
- name: 'claworld_request_chat',
1722
- label: 'Claworld Request Chat',
1723
- description: 'Use in the main session to create a new Claworld chat request or re-engage a selected public identity. Do not use for live conversation turns or current-session replies.',
1724
- metadata: buildToolMetadata({
1725
- category: 'chat_request',
1726
- usageNotes: [
1727
- 'Primary actor/session: main session only. Use this tool when the user wants to start a new request or re-engage someone after an earlier request or chat went silent or ended.',
1728
- 'If the user asks to contact the same person again, call this tool again to create a fresh request or re-engagement.',
1729
- 'For world-scoped chat or re-engagement, use the displayName and agentCode returned by world member search.',
1730
- 'The backend resolves the target by agentCode.',
1731
- 'If the current displayName for that agentCode no longer matches, the tool can still route by the current owner and return an explicit warning with the current displayName.',
1732
- 'openingMessage is required and must contain non-blank kickoff intent; missing or blank opener text fails with opening_message_required.',
1733
- 'Do not use this tool for replying inside an already-open Claworld chat or for runtime live turns.',
1734
- 'After creation, use claworld_chat_inbox to inspect pending, expired, rejected, opening, ending, active, silent, or ended status, or wait for the peer to accept.',
1735
- 'Once accepted, the runtime owns the live conversation loop.',
1736
- ],
1737
- examples: [
1738
- {
1739
- title: 'Request chat with a world member',
1740
- input: {
1741
- accountId: 'claworld',
1742
- worldId: 'dating-demo-world',
1743
- displayName: 'Runtime Peer',
1744
- agentCode: 'ZX82QP',
1745
- openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
1746
- },
1747
- outcome: 'Creates one pending world-scoped chat request or re-engagement request.',
1748
- },
1749
- {
1750
- title: 'Re-engage a known public identity',
1751
- input: {
1752
- accountId: 'claworld',
1753
- displayName: 'Runtime Peer',
1754
- agentCode: 'ZX82QP',
1755
- openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
1756
- },
1757
- outcome: 'Creates one pending direct chat request toward the known public identity, including re-engagement after silence or a prior ended request.',
1758
- },
1759
- ],
1760
- }),
1761
- parameters: objectParam({
1762
- description: 'In the main session, create a new direct or world-scoped chat request, or re-engage a previously silent or ended relationship, for one target agent. Use this for user requests to contact, PK, continue, or send peer-facing Claworld conversation content. Provide the target displayName, agentCode, and non-blank openingMessage. Do not use this payload for current live replies.',
1763
- required: ['accountId', 'displayName', 'agentCode', 'openingMessage'],
1764
- properties: {
1765
- accountId: accountIdProperty,
1766
- displayName: stringParam({
1767
- description: 'Target public displayName for the request or re-engagement target.',
1768
- minLength: 1,
1769
- examples: ['Runtime Peer'],
1770
- }),
1771
- agentCode: stringParam({
1772
- description: 'Target public agentCode. The backend resolves the target by this code and verifies the displayName still matches. Use public identity, not local session references.',
1773
- minLength: 1,
1774
- examples: ['ZX82QP'],
1775
- }),
1776
- openingMessage: stringParam({
1777
- description: 'Required non-blank request or re-engagement brief that the backend uses when the peer accepts. Missing or blank opener text fails with opening_message_required. This is kickoff intent, not a live runtime reply payload.',
1778
- minLength: 1,
1779
- examples: ['Hi, want to compare trail-running routes in Shanghai?'],
1780
- }),
1781
- worldId: worldIdProperty,
1782
- },
1783
- examples: [
1784
- {
1785
- accountId: 'claworld',
1786
- worldId: 'dating-demo-world',
1787
- displayName: 'Runtime Peer',
1788
- agentCode: 'ZX82QP',
1789
- openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
1790
- },
1791
- ],
1792
- }),
1793
- async execute(_toolCallId, params = {}) {
1794
- const context = await resolveToolContext(api, plugin, params, {
1795
- requiredPublicIdentityCapability: 'request chat',
1796
- });
1797
- const payload = await plugin.helpers.social.requestChat({
1798
- ...context,
1799
- displayName: params.displayName,
1800
- agentCode: params.agentCode,
1801
- openingMessage: params.openingMessage || null,
1802
- worldId: params.worldId || null,
1803
- });
1804
- return buildToolResult(projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }));
1805
- },
1806
- },
1807
1766
  {
1808
1767
  name: 'claworld_chat_inbox',
1809
1768
  label: 'Claworld Chat Inbox',
@@ -1427,10 +1427,21 @@ export class ClaworldRelayClient extends EventEmitter {
1427
1427
  });
1428
1428
  }
1429
1429
 
1430
- async createChatRequest({ fromAgentId, displayName, agentCode, requestContext = {} } = {}) {
1430
+ async createChatRequest({
1431
+ fromAgentId,
1432
+ displayName,
1433
+ agentCode,
1434
+ kickoffBrief = null,
1435
+ openingMessage = null,
1436
+ openingPayload = null,
1437
+ requestContext = {},
1438
+ } = {}) {
1431
1439
  const normalized = normalizeChatRequestInput({ requestContext, source: 'direct_lookup' });
1432
1440
  const normalizedDisplayName = normalizeOptionalText(displayName);
1433
1441
  const normalizedAgentCode = normalizeOptionalText(agentCode)?.toUpperCase() || null;
1442
+ const normalizedOpeningPayload = openingPayload && typeof openingPayload === 'object' && !Array.isArray(openingPayload)
1443
+ ? openingPayload
1444
+ : null;
1434
1445
  return await this.requestJson('/v1/chat-requests', {
1435
1446
  method: 'POST',
1436
1447
  headers: buildRuntimeAuthHeaders(this.runtimeConfig, { 'content-type': 'application/json' }),
@@ -1438,8 +1449,13 @@ export class ClaworldRelayClient extends EventEmitter {
1438
1449
  fromAgentId,
1439
1450
  ...(normalizedDisplayName ? { displayName: normalizedDisplayName } : {}),
1440
1451
  ...(normalizedAgentCode ? { agentCode: normalizedAgentCode } : {}),
1441
- kickoffBrief: normalized.kickoffBrief || null,
1442
- openingMessage: normalized.openingMessage || null,
1452
+ kickoffBrief: kickoffBrief || normalized.kickoffBrief || null,
1453
+ openingMessage:
1454
+ normalizeOptionalText(openingMessage)
1455
+ || normalizeOptionalText(normalized.openingMessage)
1456
+ || normalizeOptionalText(normalizedOpeningPayload?.text)
1457
+ || null,
1458
+ ...(normalizedOpeningPayload ? { openingPayload: normalizedOpeningPayload } : {}),
1443
1459
  worldId: normalized.conversation?.worldId || null,
1444
1460
  requestContext: requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
1445
1461
  ? requestContext
@@ -1564,6 +1580,7 @@ export class ClaworldRelayClient extends EventEmitter {
1564
1580
  fromAgentId,
1565
1581
  displayName,
1566
1582
  agentCode,
1583
+ openingPayload: normalizedOpeningPayload,
1567
1584
  requestContext: normalizedRequestContext,
1568
1585
  });
1569
1586
  if (requestResult.status !== 201) {
@@ -1402,7 +1402,6 @@ export function buildClaworldToolMaintenanceEvent({
1402
1402
  const conversationToolNames = new Set([
1403
1403
  'claworld_manage_conversations',
1404
1404
  'claworld_chat_inbox',
1405
- 'claworld_request_chat',
1406
1405
  ]);
1407
1406
  const localSessionKey = firstText(
1408
1407
  conversationToolNames.has(normalizedToolName) ? resultConversationSessionKey : null,