@xfxstudio/claworld 2026.4.29-testing.3 → 2026.4.29-testing.4

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.
@@ -8,7 +8,7 @@
8
8
  ],
9
9
  "name": "Claworld Persona Relay",
10
10
  "description": "Claworld relay world channel plugin for OpenClaw.",
11
- "version": "2026.4.29-testing.3",
11
+ "version": "2026.4.29-testing.4",
12
12
  "configSchema": {
13
13
  "type": "object",
14
14
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfxstudio/claworld",
3
- "version": "2026.4.29-testing.3",
3
+ "version": "2026.4.29-testing.4",
4
4
  "description": "Claworld channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -653,7 +653,10 @@ export function projectToolAccountViewResponse({
653
653
  identityPayload = null,
654
654
  } = {}) {
655
655
  const identityReady = identityPayload?.ready === true;
656
- const ready = pairingPayload?.status === 'paired' && identityReady;
656
+ const bindingReady = pairingPayload?.status === 'paired';
657
+ const ready = bindingReady && identityReady;
658
+ const relayResolved = pairingPayload?.relayAgent?.resolved ?? null;
659
+ const relayOnline = pairingPayload?.relayAgent?.online ?? null;
657
660
  const resolvedShareCard = identityPayload && Object.prototype.hasOwnProperty.call(identityPayload, 'shareCard')
658
661
  ? projectToolShareCard(identityPayload.shareCard)
659
662
  : undefined;
@@ -668,7 +671,14 @@ export function projectToolAccountViewResponse({
668
671
  reason: normalizeText(pairingPayload?.reason, null),
669
672
  bindingSource: normalizeText(pairingPayload?.bindingSource, null),
670
673
  activation: {
671
- status: pairingPayload?.status === 'paired' ? 'ready' : 'pending',
674
+ status: bindingReady ? 'ready' : 'pending',
675
+ },
676
+ diagnostics: {
677
+ toolReachable: true,
678
+ bindingReady,
679
+ publicIdentityReady: identityReady,
680
+ relayPresenceResolved: relayResolved,
681
+ relayOnline,
672
682
  },
673
683
  relay: {
674
684
  agentId: normalizeText(
@@ -678,9 +688,9 @@ export function projectToolAccountViewResponse({
678
688
  displayName: normalizeText(pairingPayload?.relayAgent?.displayName, null),
679
689
  discoverable: pairingPayload?.relayAgent?.discoverable ?? null,
680
690
  contactable: pairingPayload?.relayAgent?.contactable ?? null,
681
- online: pairingPayload?.relayAgent?.online ?? null,
682
- resolved: pairingPayload?.relayAgent?.resolved ?? null,
683
- bindingStatus: pairingPayload?.status === 'paired' ? 'bound' : 'unactivated',
691
+ online: relayOnline,
692
+ resolved: relayResolved,
693
+ bindingStatus: bindingReady ? 'bound' : 'unactivated',
684
694
  },
685
695
  profile: projectToolAccountProfile(identityPayload),
686
696
  ...projectToolAccountIdentityFields(identityPayload),
@@ -142,33 +142,6 @@ const CHAT_INBOX_FILTER_STATUSES = Object.freeze([
142
142
  'kickoff_failed',
143
143
  'ended',
144
144
  ]);
145
- const CHAT_INBOX_FILTER_KEYS = Object.freeze([
146
- 'direction',
147
- 'mode',
148
- 'status',
149
- 'worldId',
150
- 'chatRequestId',
151
- 'conversationKey',
152
- 'localSessionKey',
153
- 'counterpartyAgentId',
154
- ]);
155
- const CHAT_INBOX_FILTER_KEY_SET = new Set(CHAT_INBOX_FILTER_KEYS);
156
- const MANAGE_CONVERSATION_REQUEST_ONLY_QUERY_FIELDS = Object.freeze([
157
- 'displayName',
158
- 'agentCode',
159
- 'openingMessage',
160
- ]);
161
- const MANAGE_CONVERSATION_FILTER_ONLY_TOP_LEVEL_FIELDS = Object.freeze([
162
- 'mode',
163
- 'status',
164
- 'worldId',
165
- 'counterpartyAgentId',
166
- ]);
167
- const MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS = Object.freeze([
168
- 'chatRequestId',
169
- 'conversationKey',
170
- 'localSessionKey',
171
- ]);
172
145
 
173
146
  const TERMINAL_ACCOUNT_ACTIONS = Object.freeze([
174
147
  'view_account',
@@ -319,117 +292,6 @@ function normalizeChatInboxListFiltersInput(params = {}) {
319
292
  );
320
293
  }
321
294
 
322
- function hasProvidedToolParam(params = {}, fieldId) {
323
- if (!params || typeof params !== 'object') return false;
324
- if (!Object.prototype.hasOwnProperty.call(params, fieldId)) return false;
325
- const value = params[fieldId];
326
- if (typeof value === 'string') return normalizeText(value, null) != null;
327
- return value != null;
328
- }
329
-
330
- function buildChatInboxFiltersParam({ description, worldIdProperty } = {}) {
331
- return objectParam({
332
- description,
333
- additionalProperties: false,
334
- properties: {
335
- direction: stringParam({
336
- description: 'Filter from the current account perspective.',
337
- enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
338
- examples: ['outbound'],
339
- }),
340
- mode: stringParam({
341
- description: 'Filter to direct or world-scoped chat items.',
342
- enumValues: CHAT_INBOX_FILTER_MODES,
343
- examples: ['world'],
344
- }),
345
- status: stringParam({
346
- description: 'Filter to pending or terminal requests, or to chats by current status.',
347
- enumValues: CHAT_INBOX_FILTER_STATUSES,
348
- examples: ['active'],
349
- }),
350
- worldId: worldIdProperty,
351
- chatRequestId: stringParam({
352
- description: 'Filter to one canonical chat request id.',
353
- minLength: 1,
354
- examples: ['req_demo_1'],
355
- }),
356
- conversationKey: stringParam({
357
- description: 'Filter to one canonical conversation key.',
358
- minLength: 1,
359
- examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
360
- }),
361
- localSessionKey: stringParam({
362
- description: 'Filter to one local Claworld session reference for internal tracking, summaries, or orchestration only. Not a transport address for sending a user message to the peer.',
363
- minLength: 1,
364
- examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
365
- }),
366
- counterpartyAgentId: stringParam({
367
- description: 'Filter to one counterparty agentId.',
368
- minLength: 1,
369
- examples: ['agt_alice'],
370
- }),
371
- },
372
- });
373
- }
374
-
375
- function validateChatInboxFilterInput(filters = {}, action) {
376
- const source = normalizeObject(filters, {}) || {};
377
- for (const key of Object.keys(source)) {
378
- if (CHAT_INBOX_FILTER_KEY_SET.has(key)) continue;
379
- requireManageWorldField(`filters.${key}`, `filters.${key} is not supported for action=${action}`);
380
- }
381
- return source;
382
- }
383
-
384
- function normalizeManageConversationInboxQuery(params = {}, action) {
385
- const normalizedAction = normalizeTerminalConversationAction(action, 'list_related');
386
- const filters = validateChatInboxFilterInput(params.filters, normalizedAction);
387
-
388
- const requestOnlyField = MANAGE_CONVERSATION_REQUEST_ONLY_QUERY_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
389
- if (requestOnlyField) {
390
- requireManageWorldField(requestOnlyField, `${requestOnlyField} is only supported for action=request`);
391
- }
392
- if (hasProvidedToolParam(params, 'limit')) {
393
- requireManageWorldField('limit', `limit is not supported for action=${normalizedAction}`);
394
- }
395
-
396
- const filterOnlyField = MANAGE_CONVERSATION_FILTER_ONLY_TOP_LEVEL_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
397
- if (filterOnlyField) {
398
- requireManageWorldField(
399
- filterOnlyField,
400
- `${filterOnlyField} must be passed as filters.${filterOnlyField} for action=${normalizedAction}`,
401
- );
402
- }
403
-
404
- if (normalizedAction !== 'get_state') {
405
- const getStateOnlyField = MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
406
- if (getStateOnlyField) {
407
- requireManageWorldField(
408
- getStateOnlyField,
409
- `${getStateOnlyField} must be passed as filters.${getStateOnlyField} for action=${normalizedAction}`,
410
- );
411
- }
412
- }
413
-
414
- const mergedFilters = {
415
- ...filters,
416
- ...(!Object.prototype.hasOwnProperty.call(filters, 'direction') && hasProvidedToolParam(params, 'direction')
417
- ? { direction: params.direction }
418
- : {}),
419
- ...(normalizedAction === 'get_state'
420
- ? Object.fromEntries(
421
- MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS
422
- .filter((fieldId) => (
423
- !Object.prototype.hasOwnProperty.call(filters, fieldId)
424
- && hasProvidedToolParam(params, fieldId)
425
- ))
426
- .map((fieldId) => [fieldId, params[fieldId]]),
427
- )
428
- : {}),
429
- };
430
- return normalizeChatInboxListFiltersInput({ filters: mergedFilters });
431
- }
432
-
433
295
  function parseToolResultPayload(result = null) {
434
296
  const text = result?.content?.[0]?.text;
435
297
  if (typeof text !== 'string') return null;
@@ -1062,27 +924,10 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1062
924
  agentCode: stringParam({ description: 'Target public agent code for request.', minLength: 1 }),
1063
925
  openingMessage: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
1064
926
  worldId: worldIdProperty,
1065
- direction: stringParam({
1066
- description: 'Top-level alias for filters.direction on action=list_related/get_state.',
1067
- enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
1068
- examples: ['outbound'],
1069
- }),
1070
- filters: buildChatInboxFiltersParam({
1071
- description: 'Inbox filters for action=list_related/get_state.',
1072
- worldIdProperty,
1073
- }),
1074
- chatRequestId: stringParam({
1075
- description: 'Request id for action=accept/reject, or a top-level get_state convenience target that normalizes to filters.chatRequestId.',
1076
- minLength: 1,
1077
- }),
1078
- conversationKey: stringParam({
1079
- description: 'Conversation key for action=close, or a top-level get_state convenience target that normalizes to filters.conversationKey.',
1080
- minLength: 1,
1081
- }),
1082
- localSessionKey: stringParam({
1083
- description: 'Local conversation session key for action=close, or a top-level get_state convenience target that normalizes to filters.localSessionKey.',
1084
- minLength: 1,
1085
- }),
927
+ filters: objectParam({ description: 'List filters.', additionalProperties: true }),
928
+ chatRequestId: stringParam({ description: 'Request id for accept/reject.', minLength: 1 }),
929
+ conversationKey: stringParam({ description: 'Conversation key for get_state/close.', minLength: 1 }),
930
+ localSessionKey: stringParam({ description: 'Local conversation session key for get_state/close.', minLength: 1 }),
1086
931
  },
1087
932
  }),
1088
933
  async execute(toolCallId, params = {}) {
@@ -1094,19 +939,10 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1094
939
  });
1095
940
  return rewriteToolResultName(result, manageConversationsTool, action);
1096
941
  }
1097
- if (action === 'list_related' || action === 'get_state') {
1098
- const filters = normalizeManageConversationInboxQuery(params, action);
1099
- const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
1100
- ...params,
1101
- action: 'list',
1102
- ...(Object.keys(filters).length > 0 ? { filters } : {}),
1103
- });
1104
- return rewriteToolResultName(result, manageConversationsTool, action);
1105
- }
1106
- if (action === 'accept' || action === 'reject') {
942
+ if (['list_related', 'get_state', 'accept', 'reject'].includes(action)) {
1107
943
  const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
1108
944
  ...params,
1109
- action,
945
+ action: ['list_related', 'get_state'].includes(action) ? 'list' : action,
1110
946
  });
1111
947
  return rewriteToolResultName(result, manageConversationsTool, action);
1112
948
  }
@@ -1854,10 +1690,45 @@ function buildRegisteredTools(api, plugin) {
1854
1690
  examples: ['list', 'accept', 'reject'],
1855
1691
  }),
1856
1692
  filters: objectParam({
1857
- ...buildChatInboxFiltersParam({
1858
- description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
1859
- worldIdProperty,
1860
- }),
1693
+ description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
1694
+ properties: {
1695
+ direction: stringParam({
1696
+ description: 'Filter from the current account perspective.',
1697
+ enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
1698
+ examples: ['outbound'],
1699
+ }),
1700
+ mode: stringParam({
1701
+ description: 'Filter to direct or world-scoped chat items.',
1702
+ enumValues: CHAT_INBOX_FILTER_MODES,
1703
+ examples: ['world'],
1704
+ }),
1705
+ status: stringParam({
1706
+ description: 'Filter to pending or terminal requests, or to chats by current status.',
1707
+ enumValues: CHAT_INBOX_FILTER_STATUSES,
1708
+ examples: ['active'],
1709
+ }),
1710
+ worldId: worldIdProperty,
1711
+ chatRequestId: stringParam({
1712
+ description: 'Filter to one canonical chat request id.',
1713
+ minLength: 1,
1714
+ examples: ['req_demo_1'],
1715
+ }),
1716
+ conversationKey: stringParam({
1717
+ description: 'Filter to one canonical conversation key.',
1718
+ minLength: 1,
1719
+ examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
1720
+ }),
1721
+ localSessionKey: stringParam({
1722
+ description: 'Filter to one local Claworld session reference for internal tracking, summaries, or orchestration only. Not a transport address for sending a user message to the peer.',
1723
+ minLength: 1,
1724
+ examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
1725
+ }),
1726
+ counterpartyAgentId: stringParam({
1727
+ description: 'Filter to one counterparty agentId.',
1728
+ minLength: 1,
1729
+ examples: ['agt_alice'],
1730
+ }),
1731
+ },
1861
1732
  }),
1862
1733
  chatRequestId: stringParam({
1863
1734
  description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests. Required for action=accept or action=reject.',
@@ -2097,7 +1968,16 @@ function buildRegisteredTools(api, plugin) {
2097
1968
  expiresInSeconds: params.expiresInSeconds ?? null,
2098
1969
  });
2099
1970
  const pairedAgentId = identityPayload?.agentId || runtimeConfig.relay?.agentId || null;
2100
- const relayAgent = pairedAgentId
1971
+ const pairedRuntimeConfig = pairedAgentId
1972
+ ? {
1973
+ ...runtimeConfig,
1974
+ relay: {
1975
+ ...(runtimeConfig.relay && typeof runtimeConfig.relay === 'object' ? runtimeConfig.relay : {}),
1976
+ agentId: pairedAgentId,
1977
+ },
1978
+ }
1979
+ : runtimeConfig;
1980
+ const relayAgentFallback = pairedAgentId
2101
1981
  ? {
2102
1982
  agentId: pairedAgentId,
2103
1983
  displayName: normalizeText(
@@ -2118,6 +1998,23 @@ function buildRegisteredTools(api, plugin) {
2118
1998
  || runtimeConfig.relay?.appToken
2119
1999
  || runtimeConfig.relay?.credentialToken,
2120
2000
  );
2001
+ let relayAgent = relayAgentFallback;
2002
+ if (hasConfiguredAppToken && pairedAgentId && typeof plugin.helpers?.pairing?.resolveAgentIdentity === 'function') {
2003
+ const resolvedRelayAgent = await plugin.helpers.pairing.resolveAgentIdentity({
2004
+ cfg,
2005
+ accountId,
2006
+ runtimeConfig: pairedRuntimeConfig,
2007
+ agentId: pairedAgentId,
2008
+ });
2009
+ if (resolvedRelayAgent && typeof resolvedRelayAgent === 'object') {
2010
+ relayAgent = {
2011
+ ...relayAgentFallback,
2012
+ ...resolvedRelayAgent,
2013
+ agentId: normalizeText(resolvedRelayAgent.agentId, pairedAgentId),
2014
+ displayName: normalizeText(resolvedRelayAgent.displayName, relayAgentFallback?.displayName ?? null),
2015
+ };
2016
+ }
2017
+ }
2121
2018
  const pairingPayload = {
2122
2019
  status: hasConfiguredAppToken ? 'paired' : 'unpaired',
2123
2020
  reason: hasConfiguredAppToken
@@ -2126,15 +2023,7 @@ function buildRegisteredTools(api, plugin) {
2126
2023
  bindingSource: hasConfiguredAppToken
2127
2024
  ? 'configured_app_token'
2128
2025
  : (runtimeConfig.registration?.enabled === true ? 'registration_pending' : 'unbound'),
2129
- runtimeConfig: pairedAgentId
2130
- ? {
2131
- ...runtimeConfig,
2132
- relay: {
2133
- ...(runtimeConfig.relay && typeof runtimeConfig.relay === 'object' ? runtimeConfig.relay : {}),
2134
- agentId: pairedAgentId,
2135
- },
2136
- }
2137
- : runtimeConfig,
2026
+ runtimeConfig: pairedRuntimeConfig,
2138
2027
  relayAgent,
2139
2028
  };
2140
2029
  return buildToolResult(projectToolAccountViewResponse({