@xfxstudio/claworld 2026.7.2-testing.1 → 2026.7.8-testing.1
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 +29 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/claworld-help/SKILL.md +4 -2
- package/skills/claworld-main-session/SKILL.md +1 -1
- package/skills/claworld-manage-worlds/SKILL.md +9 -0
- package/skills/claworld-management-session/SKILL.md +10 -12
- package/src/openclaw/index.js +1 -0
- package/src/openclaw/plugin/account-identity.js +8 -2
- package/src/openclaw/plugin/claworld-channel-plugin.js +67 -79
- package/src/openclaw/plugin/register-tooling.js +150 -82
- package/src/openclaw/plugin/register.js +97 -110
- package/src/openclaw/plugin/relay-client.js +6 -2
- package/src/openclaw/plugin-version.js +9 -22
- package/src/openclaw/runtime/tool-contracts.js +2 -2
- package/src/openclaw/runtime/world-membership-helper.js +157 -0
- package/src/product-shell/contracts/chat-request-approval-policy.js +6 -0
- package/src/product-shell/contracts/search-item.js +3 -3
|
@@ -25,10 +25,6 @@ import {
|
|
|
25
25
|
} from '../runtime/working-memory.js';
|
|
26
26
|
import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
|
|
27
27
|
import { setClaworldRuntime } from './runtime.js';
|
|
28
|
-
import {
|
|
29
|
-
CHAT_REQUEST_APPROVAL_POLICY_MODES,
|
|
30
|
-
CHAT_REQUEST_APPROVAL_POLICY_ORIGIN_TYPES,
|
|
31
|
-
} from '../../product-shell/contracts/chat-request-approval-policy.js';
|
|
32
28
|
import { PUBLIC_TOOL_ACTION_CATALOG } from '../../product-shell/contracts/search-item.js';
|
|
33
29
|
import {
|
|
34
30
|
ACCOUNT_ACTIONS,
|
|
@@ -54,6 +50,8 @@ import {
|
|
|
54
50
|
projectToolManageWorldActionResponse,
|
|
55
51
|
requireManageWorldField,
|
|
56
52
|
resolveToolContext,
|
|
53
|
+
resolveToolAgentId,
|
|
54
|
+
resolveToolDisplayName,
|
|
57
55
|
stringParam,
|
|
58
56
|
withToolErrorBoundary,
|
|
59
57
|
} from './register-tooling.js';
|
|
@@ -236,13 +234,50 @@ function normalizeTerminalAccountAction(params = {}) {
|
|
|
236
234
|
Object.prototype.hasOwnProperty.call(params, 'agentProfile')
|
|
237
235
|
|| Object.prototype.hasOwnProperty.call(params, 'profile')
|
|
238
236
|
) return 'update_agent_profile';
|
|
239
|
-
if (Object.prototype.hasOwnProperty.call(params, '
|
|
240
|
-
if (Object.prototype.hasOwnProperty.call(params, '
|
|
241
|
-
if (
|
|
237
|
+
if (Object.prototype.hasOwnProperty.call(params, 'visibilityMode')) return 'set_visibility_mode';
|
|
238
|
+
if (Object.prototype.hasOwnProperty.call(params, 'contactPolicy')) return 'set_contact_policy';
|
|
239
|
+
if (Object.prototype.hasOwnProperty.call(params, 'chatRequestPolicy')) {
|
|
240
|
+
requireManageWorldField('chatRequestPolicy', 'chatRequestPolicy is not supported by claworld_manage_account; use contactPolicy');
|
|
241
|
+
}
|
|
242
242
|
if (Object.prototype.hasOwnProperty.call(params, 'proactivitySettings')) return 'set_proactivity';
|
|
243
243
|
return 'view_account';
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
function hasProvidedTerminalAccountPolicyField(params = {}, fieldId) {
|
|
247
|
+
if (!Object.prototype.hasOwnProperty.call(params, fieldId)) return false;
|
|
248
|
+
const value = params[fieldId];
|
|
249
|
+
if (value == null) return false;
|
|
250
|
+
if (typeof value === 'string') return normalizeText(value, null) != null;
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function validateTerminalAccountPolicyPayload(action, params = {}) {
|
|
255
|
+
if (action === 'set_visibility_mode') {
|
|
256
|
+
if (!normalizeText(params.visibilityMode, null)) {
|
|
257
|
+
requireManageWorldField('visibilityMode', 'visibilityMode is required for action=set_visibility_mode');
|
|
258
|
+
}
|
|
259
|
+
if (hasProvidedTerminalAccountPolicyField(params, 'contactPolicy')) {
|
|
260
|
+
requireManageWorldField('contactPolicy', 'contactPolicy is not supported for action=set_visibility_mode');
|
|
261
|
+
}
|
|
262
|
+
if (hasProvidedTerminalAccountPolicyField(params, 'chatRequestPolicy')) {
|
|
263
|
+
requireManageWorldField('chatRequestPolicy', 'chatRequestPolicy is not supported by claworld_manage_account; use contactPolicy');
|
|
264
|
+
}
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (action === 'set_contact_policy') {
|
|
268
|
+
if (!normalizeText(params.contactPolicy, null)) {
|
|
269
|
+
requireManageWorldField('contactPolicy', 'contactPolicy is required for action=set_contact_policy');
|
|
270
|
+
}
|
|
271
|
+
if (hasProvidedTerminalAccountPolicyField(params, 'visibilityMode')) {
|
|
272
|
+
requireManageWorldField('visibilityMode', 'visibilityMode is not supported for action=set_contact_policy');
|
|
273
|
+
}
|
|
274
|
+
if (hasProvidedTerminalAccountPolicyField(params, 'chatRequestPolicy')) {
|
|
275
|
+
requireManageWorldField('chatRequestPolicy', 'chatRequestPolicy is not supported by claworld_manage_account; use contactPolicy');
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
246
281
|
function normalizeTerminalWorldAction(params = {}) {
|
|
247
282
|
if (hasExplicitAction(params)) {
|
|
248
283
|
const explicitAction = normalizeText(params.action, null);
|
|
@@ -470,12 +505,12 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
470
505
|
{
|
|
471
506
|
name: accountTool,
|
|
472
507
|
label: 'Claworld Manage Account',
|
|
473
|
-
description: 'Terminal account surface for readiness, public identity, global profile, share-card generation,
|
|
508
|
+
description: 'Terminal account surface for readiness, public identity, global profile, share-card generation, visibility, inbound contact policy, and email-based identity verification.',
|
|
474
509
|
metadata: buildToolMetadata({
|
|
475
510
|
category: 'account',
|
|
476
511
|
usageNotes: [
|
|
477
512
|
'Use this human-facing account surface for identity verification, profile, policy, and subscription decisions.',
|
|
478
|
-
'Use action=view_account for readiness; update_display_name, update_agent_profile, or
|
|
513
|
+
'Use action=view_account for readiness; update_display_name, update_agent_profile, or set_contact_policy for common account mutations.',
|
|
479
514
|
'Use start_email_verification with email + optional displayName to start email-based identity verification, then complete_email_verification with email + code to finish.',
|
|
480
515
|
'Use subscribe_person or unsubscribe_person when a search/profile result exposes a person subscription target.',
|
|
481
516
|
],
|
|
@@ -488,7 +523,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
488
523
|
action: stringParam({
|
|
489
524
|
description: 'Account action.',
|
|
490
525
|
enumValues: TERMINAL_ACCOUNT_ACTIONS,
|
|
491
|
-
examples: ['view_account', 'start_email_verification', 'update_display_name', '
|
|
526
|
+
examples: ['view_account', 'start_email_verification', 'update_display_name', 'set_contact_policy'],
|
|
492
527
|
}),
|
|
493
528
|
displayName: stringParam({
|
|
494
529
|
description: 'Public-facing display name for update_display_name or start_email_verification.',
|
|
@@ -507,11 +542,15 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
507
542
|
description: 'Agent-facing profile/personality text for update_agent_profile.',
|
|
508
543
|
examples: ['偏主动但会先确认边界,擅长总结和约局。'],
|
|
509
544
|
}),
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
545
|
+
visibilityMode: stringParam({
|
|
546
|
+
description: 'Account visibility mode: public is searchable, unlisted is explicit-identity reachable, private is not publicly reachable.',
|
|
547
|
+
enumValues: ['public', 'unlisted', 'private'],
|
|
548
|
+
examples: ['public', 'unlisted', 'private'],
|
|
549
|
+
}),
|
|
550
|
+
contactPolicy: stringParam({
|
|
551
|
+
description: 'Inbound contact policy: open accepts eligible requests, approval_required keeps the request path open but requires review, closed blocks new inbound contact.',
|
|
552
|
+
enumValues: ['open', 'approval_required', 'closed'],
|
|
553
|
+
examples: ['open', 'approval_required', 'closed'],
|
|
515
554
|
}),
|
|
516
555
|
proactivitySettings: objectParam({
|
|
517
556
|
description: 'Account-level proactive-management settings.',
|
|
@@ -554,6 +593,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
554
593
|
}),
|
|
555
594
|
async execute(toolCallId, params = {}) {
|
|
556
595
|
const action = normalizeTerminalAccountAction(params);
|
|
596
|
+
validateTerminalAccountPolicyPayload(action, params);
|
|
557
597
|
const subscriptionTargetId = normalizeText(params.targetAgentId, normalizeText(params.targetId, null));
|
|
558
598
|
if (action === 'subscribe_person') {
|
|
559
599
|
if (!subscriptionTargetId) requireManageWorldField('targetAgentId', 'targetAgentId is required for action=subscribe_person');
|
|
@@ -641,14 +681,20 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
641
681
|
profile: params.profile,
|
|
642
682
|
humanProfile: params.humanProfile,
|
|
643
683
|
agentProfile: params.agentProfile,
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
chatRequestApprovalPolicy: params.chatRequestApprovalPolicy || null,
|
|
684
|
+
visibilityMode: params.visibilityMode,
|
|
685
|
+
contactPolicy: params.contactPolicy,
|
|
647
686
|
proactivitySettings: params.proactivitySettings,
|
|
648
687
|
generateShareCard,
|
|
649
688
|
shareCardVariant: params.shareCardVariant ?? null,
|
|
650
689
|
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
651
690
|
});
|
|
691
|
+
if (action === 'update_display_name') {
|
|
692
|
+
return buildToolResult(projectToolAccountMutationResponse({
|
|
693
|
+
action,
|
|
694
|
+
accountId: context.accountId,
|
|
695
|
+
identityPayload: payload,
|
|
696
|
+
}));
|
|
697
|
+
}
|
|
652
698
|
return buildTerminalActionResult({ tool: accountTool, action, payload });
|
|
653
699
|
},
|
|
654
700
|
},
|
|
@@ -661,7 +707,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
661
707
|
usageNotes: [
|
|
662
708
|
'scope=worlds searches or browses visible worlds.',
|
|
663
709
|
'scope=world_members searches members in an authorized world.',
|
|
664
|
-
'scope=people searches globally
|
|
710
|
+
'scope=people searches globally public identities; unlisted people require explicit identity/profile lookup.',
|
|
665
711
|
'scope=mixed combines world, optional world-member, and global people search results in one SearchItemEnvelope list.',
|
|
666
712
|
],
|
|
667
713
|
}),
|
|
@@ -851,6 +897,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
851
897
|
category: 'world_management',
|
|
852
898
|
usageNotes: [
|
|
853
899
|
'action=join_world joins a visible world with world-scoped profile text.',
|
|
900
|
+
'action=list_pending_invites lists pending world invitations received by the current account.',
|
|
854
901
|
'action=create_world creates an owner-managed world.',
|
|
855
902
|
'Owner governance and member self-service actions use terminal action names such as update_world, publish_broadcast, and update_world_profile.',
|
|
856
903
|
'Subscription, activity, and member-list actions are backed by the product-shell terminal routes.',
|
|
@@ -970,6 +1017,18 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
970
1017
|
});
|
|
971
1018
|
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
972
1019
|
}
|
|
1020
|
+
if (action === 'list_pending_invites') {
|
|
1021
|
+
const context = await resolveToolContext(api, plugin, params, {
|
|
1022
|
+
requiredPublicIdentityCapability: 'list pending world invites',
|
|
1023
|
+
});
|
|
1024
|
+
const payload = await plugin.runtime.productShell.membership.listPendingInvites({
|
|
1025
|
+
...context,
|
|
1026
|
+
status: params.status || 'pending',
|
|
1027
|
+
includeDisabled: params.includeDisabled !== false,
|
|
1028
|
+
limit: params.limit ?? null,
|
|
1029
|
+
});
|
|
1030
|
+
return buildTerminalActionResult({ tool: manageWorldsTool, action, payload });
|
|
1031
|
+
}
|
|
973
1032
|
if (action === 'list_invites') {
|
|
974
1033
|
const worldId = normalizeText(params.worldId, null);
|
|
975
1034
|
if (!worldId) requireManageWorldField('worldId');
|
|
@@ -1200,43 +1259,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1200
1259
|
enumValues: ['en', 'zh'],
|
|
1201
1260
|
examples: ['en', 'zh'],
|
|
1202
1261
|
});
|
|
1203
|
-
const chatRequestApprovalPolicyProperty = objectParam({
|
|
1204
|
-
description: 'Backend-managed inbound chat-request policy for this account.',
|
|
1205
|
-
required: ['mode'],
|
|
1206
|
-
properties: {
|
|
1207
|
-
mode: stringParam({
|
|
1208
|
-
description: 'Policy mode controlling which new inbound chat requests auto-accept.',
|
|
1209
|
-
enumValues: CHAT_REQUEST_APPROVAL_POLICY_MODES,
|
|
1210
|
-
examples: ['open', 'manual_review'],
|
|
1211
|
-
}),
|
|
1212
|
-
blocks: objectParam({
|
|
1213
|
-
description: 'Optional deny rules applied before the allow mode is evaluated.',
|
|
1214
|
-
properties: {
|
|
1215
|
-
originTypes: arrayParam({
|
|
1216
|
-
description: 'Canonical request origin types that should always be rejected.',
|
|
1217
|
-
items: stringParam({
|
|
1218
|
-
enumValues: CHAT_REQUEST_APPROVAL_POLICY_ORIGIN_TYPES,
|
|
1219
|
-
}),
|
|
1220
|
-
examples: [['world_broadcast']],
|
|
1221
|
-
}),
|
|
1222
|
-
worldIds: arrayParam({
|
|
1223
|
-
description: 'World ids that should always be rejected.',
|
|
1224
|
-
items: stringParam({}),
|
|
1225
|
-
examples: [['dating-demo-world']],
|
|
1226
|
-
}),
|
|
1227
|
-
},
|
|
1228
|
-
}),
|
|
1229
|
-
},
|
|
1230
|
-
examples: [
|
|
1231
|
-
{
|
|
1232
|
-
mode: 'trusted_or_world',
|
|
1233
|
-
blocks: {
|
|
1234
|
-
originTypes: ['world_broadcast'],
|
|
1235
|
-
worldIds: [],
|
|
1236
|
-
},
|
|
1237
|
-
},
|
|
1238
|
-
],
|
|
1239
|
-
});
|
|
1240
1262
|
const worldIdProperty = stringParam({
|
|
1241
1263
|
description: 'Canonical world id returned by claworld_search(scope=worlds) or claworld_manage_worlds(action=get_world).',
|
|
1242
1264
|
minLength: 1,
|
|
@@ -1925,20 +1947,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1925
1947
|
},
|
|
1926
1948
|
outcome: 'Stores the current account profile text. Pass an empty string to clear it.',
|
|
1927
1949
|
},
|
|
1928
|
-
{
|
|
1929
|
-
title: 'Update the inbound chat policy',
|
|
1930
|
-
input: {
|
|
1931
|
-
accountId: 'claworld',
|
|
1932
|
-
action: 'update_chat_policy',
|
|
1933
|
-
chatRequestApprovalPolicy: {
|
|
1934
|
-
mode: 'trusted_or_world',
|
|
1935
|
-
blocks: {
|
|
1936
|
-
originTypes: ['world_broadcast'],
|
|
1937
|
-
},
|
|
1938
|
-
},
|
|
1939
|
-
},
|
|
1940
|
-
outcome: 'Stores the account-level chat-request policy in the backend and returns the updated policy snapshot.',
|
|
1941
|
-
},
|
|
1942
1950
|
],
|
|
1943
1951
|
}),
|
|
1944
1952
|
parameters: objectParam({
|
|
@@ -1947,9 +1955,9 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1947
1955
|
properties: {
|
|
1948
1956
|
accountId: accountIdProperty,
|
|
1949
1957
|
action: stringParam({
|
|
1950
|
-
description: 'Account action. Defaults to view; inferred from displayName
|
|
1958
|
+
description: 'Account action. Defaults to view; inferred from displayName or profile when omitted.',
|
|
1951
1959
|
enumValues: ACCOUNT_ACTIONS,
|
|
1952
|
-
examples: ['view', 'update_identity', 'update_profile'
|
|
1960
|
+
examples: ['view', 'update_identity', 'update_profile'],
|
|
1953
1961
|
}),
|
|
1954
1962
|
displayName: stringParam({
|
|
1955
1963
|
description: 'Public-facing display name. Required for action=update_identity. # is reserved and must not appear here.',
|
|
@@ -1960,7 +1968,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1960
1968
|
description: 'Global plain-text profile for this account. Maximum 500 characters. Use an empty string to clear it. HTML is not supported.',
|
|
1961
1969
|
examples: ['喜欢慢节奏介绍和小范围世界,也愿意先让 agent 帮我做初步认识。🙂'],
|
|
1962
1970
|
}),
|
|
1963
|
-
chatRequestApprovalPolicy: chatRequestApprovalPolicyProperty,
|
|
1964
1971
|
generateShareCard: booleanParam({
|
|
1965
1972
|
description: 'When true, return a temporary public identity card URL. Defaults to false for view and true for update_identity.',
|
|
1966
1973
|
}),
|
|
@@ -1988,13 +1995,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1988
1995
|
action: 'update_profile',
|
|
1989
1996
|
profile: '喜欢慢节奏介绍和小范围世界,也愿意先让 agent 帮我做初步认识。🙂',
|
|
1990
1997
|
},
|
|
1991
|
-
{
|
|
1992
|
-
accountId: 'claworld',
|
|
1993
|
-
action: 'update_chat_policy',
|
|
1994
|
-
chatRequestApprovalPolicy: {
|
|
1995
|
-
mode: 'manual_review',
|
|
1996
|
-
},
|
|
1997
|
-
},
|
|
1998
1998
|
],
|
|
1999
1999
|
}),
|
|
2000
2000
|
async execute(_toolCallId, params = {}) {
|
|
@@ -2040,26 +2040,6 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2040
2040
|
}));
|
|
2041
2041
|
}
|
|
2042
2042
|
|
|
2043
|
-
if (action === 'update_chat_policy') {
|
|
2044
|
-
const context = await resolveToolContext(api, plugin, params);
|
|
2045
|
-
const chatRequestApprovalPolicy = normalizeObject(params.chatRequestApprovalPolicy, null);
|
|
2046
|
-
if (!chatRequestApprovalPolicy) {
|
|
2047
|
-
requireManageWorldField(
|
|
2048
|
-
'chatRequestApprovalPolicy',
|
|
2049
|
-
'chatRequestApprovalPolicy is required for action=update_chat_policy',
|
|
2050
|
-
);
|
|
2051
|
-
}
|
|
2052
|
-
const payload = await plugin.runtime.productShell.profile.updateChatRequestApprovalPolicy({
|
|
2053
|
-
...context,
|
|
2054
|
-
chatRequestApprovalPolicy,
|
|
2055
|
-
});
|
|
2056
|
-
return buildToolResult(projectToolAccountMutationResponse({
|
|
2057
|
-
action,
|
|
2058
|
-
accountId: context.accountId,
|
|
2059
|
-
identityPayload: payload,
|
|
2060
|
-
}));
|
|
2061
|
-
}
|
|
2062
|
-
|
|
2063
2043
|
const context = await resolveToolContext(api, plugin, params);
|
|
2064
2044
|
const cfg = context.cfg || await loadCurrentConfig(api);
|
|
2065
2045
|
const accountId = context.accountId;
|
|
@@ -2074,7 +2054,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2074
2054
|
shareCardVariant: params.shareCardVariant ?? null,
|
|
2075
2055
|
expiresInSeconds: params.expiresInSeconds ?? null,
|
|
2076
2056
|
});
|
|
2077
|
-
const pairedAgentId = identityPayload
|
|
2057
|
+
const pairedAgentId = resolveToolAgentId(identityPayload, runtimeConfig.relay?.agentId || null);
|
|
2078
2058
|
const pairedRuntimeConfig = pairedAgentId
|
|
2079
2059
|
? {
|
|
2080
2060
|
...runtimeConfig,
|
|
@@ -2087,15 +2067,15 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2087
2067
|
const relayAgentFallback = pairedAgentId
|
|
2088
2068
|
? {
|
|
2089
2069
|
agentId: pairedAgentId,
|
|
2090
|
-
displayName:
|
|
2091
|
-
identityPayload
|
|
2070
|
+
displayName: resolveToolDisplayName(
|
|
2071
|
+
identityPayload,
|
|
2092
2072
|
normalizeText(
|
|
2093
|
-
|
|
2094
|
-
normalizeText(runtimeConfig?.
|
|
2073
|
+
runtimeConfig?.name,
|
|
2074
|
+
normalizeText(runtimeConfig?.registration?.displayName, null),
|
|
2095
2075
|
),
|
|
2096
2076
|
),
|
|
2097
|
-
|
|
2098
|
-
|
|
2077
|
+
visibilityMode: null,
|
|
2078
|
+
contactPolicy: null,
|
|
2099
2079
|
online: null,
|
|
2100
2080
|
resolved: null,
|
|
2101
2081
|
}
|
|
@@ -2113,7 +2093,13 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2113
2093
|
agentId: pairedAgentId,
|
|
2114
2094
|
})
|
|
2115
2095
|
: null;
|
|
2116
|
-
const
|
|
2096
|
+
const accountPayload = normalizeObject(identityStatus?.accountView, null)
|
|
2097
|
+
|| (normalizeObject(identityStatus?.relay, null) ? identityStatus : null);
|
|
2098
|
+
const accountViewAccount = normalizeObject(accountPayload?.account, null);
|
|
2099
|
+
const accountViewDiagnostics = normalizeObject(accountPayload?.diagnostics, null);
|
|
2100
|
+
const emailVerified = identityStatus?.emailVerified === true
|
|
2101
|
+
|| accountViewAccount?.emailVerified === true
|
|
2102
|
+
|| accountViewDiagnostics?.emailVerified === true;
|
|
2117
2103
|
const bindingReady = hasConfiguredAppToken && Boolean(pairedAgentId);
|
|
2118
2104
|
const bindingStatus = hasConfiguredAppToken
|
|
2119
2105
|
? (bindingReady ? 'bound' : 'identity_unresolved')
|
|
@@ -2140,8 +2126,8 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2140
2126
|
bindingReady,
|
|
2141
2127
|
bindingStatus,
|
|
2142
2128
|
emailVerified,
|
|
2143
|
-
email: identityStatus?.email || null,
|
|
2144
|
-
verifiedAt: identityStatus?.verifiedAt || null,
|
|
2129
|
+
email: identityStatus?.email || accountViewAccount?.email || null,
|
|
2130
|
+
verifiedAt: identityStatus?.verifiedAt || accountViewAccount?.verifiedAt || null,
|
|
2145
2131
|
reason: hasConfiguredAppToken
|
|
2146
2132
|
? (pairedAgentId ? null : 'missing_agent_id')
|
|
2147
2133
|
: 'missing_app_token',
|
|
@@ -2155,6 +2141,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
2155
2141
|
accountId,
|
|
2156
2142
|
pairingPayload,
|
|
2157
2143
|
identityPayload,
|
|
2144
|
+
accountPayload,
|
|
2158
2145
|
}));
|
|
2159
2146
|
},
|
|
2160
2147
|
},
|
|
@@ -2,7 +2,10 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
3
|
import { resolveClaworldRuntimeConfig } from './config-schema.js';
|
|
4
4
|
import { buildRuntimeAuthHeaders } from './account-identity.js';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
CLAWORLD_OPENCLAW_PLUGIN_CLIENT,
|
|
7
|
+
CLAWORLD_PLUGIN_CURRENT_VERSION,
|
|
8
|
+
} from '../plugin-version.js';
|
|
6
9
|
import { createRelayEventProtocol } from '../protocol/relay-event-protocol.js';
|
|
7
10
|
import { createInboundSessionRouter } from '../runtime/inbound-session-router.js';
|
|
8
11
|
import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.js';
|
|
@@ -372,6 +375,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
372
375
|
type: 'auth',
|
|
373
376
|
agentId,
|
|
374
377
|
credential,
|
|
378
|
+
client: CLAWORLD_OPENCLAW_PLUGIN_CLIENT,
|
|
375
379
|
clientVersion,
|
|
376
380
|
bridgeProtocol: this.protocol.version,
|
|
377
381
|
});
|
|
@@ -552,7 +556,7 @@ export class ClaworldRelayClient extends EventEmitter {
|
|
|
552
556
|
config,
|
|
553
557
|
agentId,
|
|
554
558
|
credential = null,
|
|
555
|
-
clientVersion =
|
|
559
|
+
clientVersion = CLAWORLD_PLUGIN_CURRENT_VERSION,
|
|
556
560
|
sessionTarget,
|
|
557
561
|
fallbackTarget,
|
|
558
562
|
} = {}) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import repoPackageJson from '../../package.json' with { type: 'json' };
|
|
2
2
|
|
|
3
3
|
export const CLAWORLD_PLUGIN_PACKAGE_NAME = '@xfxstudio/claworld';
|
|
4
|
-
export const
|
|
4
|
+
export const CLAWORLD_CLIENT_HEADER = 'x-claworld-client';
|
|
5
|
+
export const CLAWORLD_CLIENT_VERSION_HEADER = 'x-claworld-client-version';
|
|
6
|
+
export const CLAWORLD_CLIENT_CHANNEL_HEADER = 'x-claworld-client-channel';
|
|
7
|
+
export const CLAWORLD_OPENCLAW_PLUGIN_CLIENT = 'openclaw-plugin';
|
|
5
8
|
|
|
6
9
|
function normalizeText(value, fallback = null) {
|
|
7
10
|
if (value == null) return fallback;
|
|
@@ -9,15 +12,6 @@ function normalizeText(value, fallback = null) {
|
|
|
9
12
|
return normalized || fallback;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
|
-
function normalizeHeaderValue(value) {
|
|
13
|
-
if (Array.isArray(value)) {
|
|
14
|
-
return normalizeHeaderValue(value[0]);
|
|
15
|
-
}
|
|
16
|
-
const normalized = normalizeText(value, null);
|
|
17
|
-
if (!normalized) return null;
|
|
18
|
-
return normalized.split(',')[0]?.trim() || null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
15
|
export function normalizeClaworldPluginVersion(value, fallback = null) {
|
|
22
16
|
const normalized = normalizeText(value, null);
|
|
23
17
|
if (!normalized) return fallback;
|
|
@@ -39,16 +33,9 @@ function resolveCurrentPluginVersion() {
|
|
|
39
33
|
|
|
40
34
|
export const CLAWORLD_PLUGIN_CURRENT_VERSION = resolveCurrentPluginVersion();
|
|
41
35
|
|
|
42
|
-
export function
|
|
43
|
-
const
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
normalizedVersion: normalizeClaworldPluginVersion(rawVersion, null),
|
|
48
|
-
source: rawVersion ? CLAWORLD_PLUGIN_VERSION_HEADER : null,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function buildClaworldRelayClientVersion(version = CLAWORLD_PLUGIN_CURRENT_VERSION) {
|
|
53
|
-
return `claworld-plugin/${normalizeClaworldPluginVersion(version, CLAWORLD_PLUGIN_CURRENT_VERSION)}`;
|
|
36
|
+
export function inferClaworldClientChannel(version = CLAWORLD_PLUGIN_CURRENT_VERSION, fallback = null) {
|
|
37
|
+
const normalized = normalizeClaworldPluginVersion(version, null);
|
|
38
|
+
if (!normalized) return fallback;
|
|
39
|
+
if (/-testing(?:\.|$)/.test(normalized)) return 'testing';
|
|
40
|
+
return 'stable';
|
|
54
41
|
}
|
|
@@ -583,8 +583,8 @@ function projectToolAgentSummary(agent = {}) {
|
|
|
583
583
|
displayName: normalizeText(agent.displayName, null),
|
|
584
584
|
identity: normalizeText(agent.publicIdentity?.displayIdentity, null),
|
|
585
585
|
online: agent.online === true,
|
|
586
|
-
|
|
587
|
-
|
|
586
|
+
visibilityMode: normalizeText(agent.visibilityMode, null),
|
|
587
|
+
contactPolicy: normalizeText(agent.contactPolicy, null),
|
|
588
588
|
};
|
|
589
589
|
}
|
|
590
590
|
|
|
@@ -15,6 +15,23 @@ function normalizeOptionalBoolean(value, fallback = null) {
|
|
|
15
15
|
return fallback;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function normalizeOptionalInteger(value, fallback = null) {
|
|
19
|
+
const parsed = Number(value);
|
|
20
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
21
|
+
return Math.trunc(parsed);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizePositiveInteger(value, fallback = null) {
|
|
25
|
+
const parsed = Number(value);
|
|
26
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
27
|
+
return Math.max(1, Math.trunc(parsed));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function normalizeStringList(values = []) {
|
|
31
|
+
if (!Array.isArray(values)) return [];
|
|
32
|
+
return [...new Set(values.map((value) => normalizeText(value, null)).filter(Boolean))];
|
|
33
|
+
}
|
|
34
|
+
|
|
18
35
|
function normalizeWorldRole(worldRole, fallback = null) {
|
|
19
36
|
const normalized = normalizeText(worldRole, fallback);
|
|
20
37
|
return ['owner', 'member'].includes(normalized) ? normalized : fallback;
|
|
@@ -38,6 +55,97 @@ function normalizeManagedWorldMembership(payload = {}) {
|
|
|
38
55
|
};
|
|
39
56
|
}
|
|
40
57
|
|
|
58
|
+
function normalizePendingInviteAction(action = null) {
|
|
59
|
+
if (!action || typeof action !== 'object' || Array.isArray(action)) return null;
|
|
60
|
+
return {
|
|
61
|
+
action: normalizeText(action.action, null),
|
|
62
|
+
tool: normalizeText(action.tool, null),
|
|
63
|
+
worldId: normalizeText(action.worldId, null),
|
|
64
|
+
requiredFields: normalizeStringList(action.requiredFields),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeParticipantContextField(field = null) {
|
|
69
|
+
if (!field || typeof field !== 'object' || Array.isArray(field)) return null;
|
|
70
|
+
return {
|
|
71
|
+
fieldId: normalizeText(field.fieldId, null),
|
|
72
|
+
label: normalizeText(field.label, null),
|
|
73
|
+
description: normalizeText(field.description, null),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizeJoinPlan(plan = null) {
|
|
78
|
+
if (!plan || typeof plan !== 'object' || Array.isArray(plan)) return null;
|
|
79
|
+
return {
|
|
80
|
+
worldId: normalizeText(plan.worldId, null),
|
|
81
|
+
participantContextField: normalizeParticipantContextField(plan.participantContextField),
|
|
82
|
+
nextAction: normalizeText(plan.nextAction, null),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizeInviterProfile(inviter = null) {
|
|
87
|
+
if (!inviter || typeof inviter !== 'object' || Array.isArray(inviter)) return null;
|
|
88
|
+
return {
|
|
89
|
+
agentId: normalizeText(inviter.agentId, null),
|
|
90
|
+
displayName: normalizeText(inviter.displayName, null),
|
|
91
|
+
publicIdentity: normalizeText(inviter.publicIdentity, null),
|
|
92
|
+
profile: normalizeText(inviter.profile, null),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeInviteLifecycle(lifecycle = null) {
|
|
97
|
+
if (!lifecycle || typeof lifecycle !== 'object' || Array.isArray(lifecycle)) return null;
|
|
98
|
+
return {
|
|
99
|
+
status: normalizeText(lifecycle.status, null),
|
|
100
|
+
expiresAt: normalizeText(lifecycle.expiresAt, null),
|
|
101
|
+
expirationPolicy: normalizeText(lifecycle.expirationPolicy, null),
|
|
102
|
+
acceptedAt: normalizeText(lifecycle.acceptedAt, null),
|
|
103
|
+
inviteRevokedAt: normalizeText(lifecycle.inviteRevokedAt, null),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function normalizePendingWorldInvite(payload = {}) {
|
|
108
|
+
return {
|
|
109
|
+
invitationId: normalizeText(payload.invitationId, null),
|
|
110
|
+
membershipId: normalizeText(payload.membershipId, null),
|
|
111
|
+
agentId: normalizeText(payload.agentId, null),
|
|
112
|
+
worldId: normalizeText(payload.worldId, null),
|
|
113
|
+
displayName: normalizeText(payload.displayName, null),
|
|
114
|
+
worldContextText: normalizeText(payload.worldContextText, null),
|
|
115
|
+
participantContextField: normalizeParticipantContextField(payload.participantContextField),
|
|
116
|
+
joinPlan: normalizeJoinPlan(payload.joinPlan),
|
|
117
|
+
membershipStatus: normalizeText(payload.membershipStatus, null),
|
|
118
|
+
status: normalizeText(payload.status, null),
|
|
119
|
+
invitedByAgentId: normalizeText(payload.invitedByAgentId, null),
|
|
120
|
+
invitedByDisplayName: normalizeText(payload.invitedByDisplayName, null),
|
|
121
|
+
invitedByPublicIdentity: normalizeText(payload.invitedByPublicIdentity, null),
|
|
122
|
+
inviter: normalizeInviterProfile(payload.inviter),
|
|
123
|
+
invitedAt: normalizeText(payload.invitedAt, null),
|
|
124
|
+
inviteMessage: normalizeText(payload.inviteMessage, null),
|
|
125
|
+
expiresAt: normalizeText(payload.expiresAt, null),
|
|
126
|
+
expirationPolicy: normalizeText(payload.expirationPolicy, null),
|
|
127
|
+
lifecycle: normalizeInviteLifecycle(payload.lifecycle),
|
|
128
|
+
membershipUpdatedAt: normalizeText(payload.membershipUpdatedAt, null),
|
|
129
|
+
worldUpdatedAt: normalizeText(payload.worldUpdatedAt, null),
|
|
130
|
+
nextAction: normalizeText(payload.nextAction, null),
|
|
131
|
+
nextActions: Array.isArray(payload.nextActions)
|
|
132
|
+
? payload.nextActions.map((action) => normalizePendingInviteAction(action)).filter(Boolean)
|
|
133
|
+
: [],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function normalizePendingWorldInviteList(payload = {}) {
|
|
138
|
+
return {
|
|
139
|
+
agentId: normalizeText(payload.agentId, null),
|
|
140
|
+
status: normalizeText(payload.status, null),
|
|
141
|
+
items: Array.isArray(payload.items)
|
|
142
|
+
? payload.items.map((item) => normalizePendingWorldInvite(item))
|
|
143
|
+
: [],
|
|
144
|
+
totalItems: normalizeOptionalInteger(payload.totalItems, 0),
|
|
145
|
+
nextAction: normalizeText(payload.nextAction, null),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
41
149
|
function normalizeMembershipList(payload = {}) {
|
|
42
150
|
return {
|
|
43
151
|
items: Array.isArray(payload.items)
|
|
@@ -116,6 +224,55 @@ export async function fetchWorldMemberships({
|
|
|
116
224
|
return normalizeMembershipList(result.body);
|
|
117
225
|
}
|
|
118
226
|
|
|
227
|
+
export async function fetchPendingWorldInvites({
|
|
228
|
+
cfg = {},
|
|
229
|
+
accountId = null,
|
|
230
|
+
runtimeConfig = null,
|
|
231
|
+
agentId = null,
|
|
232
|
+
status = 'pending',
|
|
233
|
+
includeDisabled = true,
|
|
234
|
+
limit = null,
|
|
235
|
+
fetchImpl,
|
|
236
|
+
logger = console,
|
|
237
|
+
} = {}) {
|
|
238
|
+
if (typeof fetchImpl !== 'function') {
|
|
239
|
+
throw new Error('fetch is unavailable for claworld world membership helper');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const resolvedAgentId = normalizeText(agentId, null);
|
|
243
|
+
if (!resolvedAgentId) {
|
|
244
|
+
throw new Error('claworld world membership helper requires agentId');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const resolvedRuntimeConfig = runtimeConfig || resolveClaworldRuntimeConfig(cfg, accountId);
|
|
248
|
+
const baseUrl = normalizeRelayHttpBaseUrl(resolvedRuntimeConfig.serverUrl);
|
|
249
|
+
const requestUrl = new URL(`${baseUrl}/v1/world-invitations`);
|
|
250
|
+
requestUrl.searchParams.set('agentId', resolvedAgentId);
|
|
251
|
+
requestUrl.searchParams.set('status', normalizeText(status, 'pending'));
|
|
252
|
+
requestUrl.searchParams.set('includeDisabled', includeDisabled ? 'true' : 'false');
|
|
253
|
+
const normalizedLimit = normalizePositiveInteger(limit, null);
|
|
254
|
+
if (normalizedLimit) requestUrl.searchParams.set('limit', String(normalizedLimit));
|
|
255
|
+
const result = await fetchJson(fetchImpl, requestUrl.toString(), {
|
|
256
|
+
headers: buildRuntimeAuthHeaders(resolvedRuntimeConfig, {
|
|
257
|
+
accept: 'application/json',
|
|
258
|
+
...(resolvedRuntimeConfig.apiKey ? { 'x-api-key': resolvedRuntimeConfig.apiKey } : {}),
|
|
259
|
+
}),
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (!result.ok) {
|
|
263
|
+
logger.error?.('[claworld:membership] pending world invites fetch failed', {
|
|
264
|
+
status: result.status,
|
|
265
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
266
|
+
body: result.body,
|
|
267
|
+
});
|
|
268
|
+
throw createWorldMembershipHttpError('list_pending_invites', result, {
|
|
269
|
+
accountId: resolvedRuntimeConfig.accountId || accountId || null,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return normalizePendingWorldInviteList(result.body);
|
|
274
|
+
}
|
|
275
|
+
|
|
119
276
|
export async function fetchWorldMembership({
|
|
120
277
|
cfg = {},
|
|
121
278
|
accountId = null,
|
|
@@ -5,6 +5,7 @@ const SUPPORTED_MODES = Object.freeze([
|
|
|
5
5
|
'trusted_only',
|
|
6
6
|
'trusted_or_world',
|
|
7
7
|
'open',
|
|
8
|
+
'reject_all',
|
|
8
9
|
]);
|
|
9
10
|
const SUPPORTED_ORIGIN_TYPES = Object.freeze([
|
|
10
11
|
'chat_request',
|
|
@@ -59,6 +60,11 @@ export function normalizeChatRequestApprovalMode(value, fallback = DEFAULT_MODE)
|
|
|
59
60
|
case 'auto_accept':
|
|
60
61
|
case 'all':
|
|
61
62
|
return 'open';
|
|
63
|
+
case 'reject':
|
|
64
|
+
case 'reject_all':
|
|
65
|
+
case 'closed':
|
|
66
|
+
case 'do_not_disturb':
|
|
67
|
+
return 'reject_all';
|
|
62
68
|
default:
|
|
63
69
|
return SUPPORTED_MODES.includes(fallback) ? fallback : DEFAULT_MODE;
|
|
64
70
|
}
|