@xfxstudio/claworld 0.2.13 → 0.2.15

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 (58) hide show
  1. package/README.md +4 -4
  2. package/index.js +0 -1
  3. package/openclaw.plugin.json +1 -97
  4. package/package.json +1 -1
  5. package/skills/claworld-help/SKILL.md +47 -27
  6. package/skills/claworld-join-and-chat/SKILL.md +13 -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 +73 -319
  10. package/src/openclaw/plugin/config-schema.js +1 -55
  11. package/src/openclaw/plugin/managed-config.js +1 -42
  12. package/src/openclaw/plugin/onboarding.js +1 -1
  13. package/src/openclaw/plugin/register.js +302 -233
  14. package/src/openclaw/plugin/relay-client.js +9 -6
  15. package/src/openclaw/runtime/product-shell-helper.js +11 -364
  16. package/src/openclaw/runtime/tool-contracts.js +0 -182
  17. package/src/openclaw/runtime/tool-inventory.js +4 -27
  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/constants.js +0 -14
  22. package/src/product-shell/agent-cards/card-routes.js +0 -64
  23. package/src/product-shell/agent-cards/card-service.js +0 -287
  24. package/src/product-shell/agent-cards/spec-builder.js +0 -167
  25. package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
  26. package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
  27. package/src/product-shell/agent-cards/svg-renderer.js +0 -325
  28. package/src/product-shell/agent-cards/template-registry.js +0 -131
  29. package/src/product-shell/catalog/default-world-catalog.js +0 -38
  30. package/src/product-shell/contracts/candidate-feed.js +0 -393
  31. package/src/product-shell/contracts/world-manifest.js +0 -369
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
  33. package/src/product-shell/feedback/feedback-contract.js +0 -13
  34. package/src/product-shell/feedback/feedback-routes.js +0 -98
  35. package/src/product-shell/feedback/feedback-service.js +0 -252
  36. package/src/product-shell/index.js +0 -212
  37. package/src/product-shell/matching/matchmaking-service.js +0 -395
  38. package/src/product-shell/membership/membership-service.js +0 -284
  39. package/src/product-shell/onboarding/onboarding-routes.js +0 -37
  40. package/src/product-shell/onboarding/onboarding-service.js +0 -222
  41. package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
  42. package/src/product-shell/profile/profile-service.js +0 -142
  43. package/src/product-shell/profile/public-identity-routes.js +0 -160
  44. package/src/product-shell/profile/public-identity-service.js +0 -192
  45. package/src/product-shell/search/search-service.js +0 -393
  46. package/src/product-shell/social/chat-request-approval-policy.js +0 -332
  47. package/src/product-shell/social/chat-request-routes.js +0 -130
  48. package/src/product-shell/social/chat-request-service.js +0 -723
  49. package/src/product-shell/social/friend-routes.js +0 -82
  50. package/src/product-shell/social/friend-service.js +0 -557
  51. package/src/product-shell/social/social-routes.js +0 -21
  52. package/src/product-shell/social/social-service.js +0 -136
  53. package/src/product-shell/worlds/world-admin-service.js +0 -486
  54. package/src/product-shell/worlds/world-authorization.js +0 -136
  55. package/src/product-shell/worlds/world-broadcast-service.js +0 -296
  56. package/src/product-shell/worlds/world-routes.js +0 -403
  57. package/src/product-shell/worlds/world-service.js +0 -89
  58. package/src/product-shell/worlds/world-text.js +0 -75
@@ -23,6 +23,10 @@ import {
23
23
  normalizeBackendMissingField,
24
24
  normalizeBackendPublicIdentity,
25
25
  } from '../runtime/backend-error-context.js';
26
+ import {
27
+ CHAT_REQUEST_APPROVAL_POLICY_MODES,
28
+ CHAT_REQUEST_APPROVAL_POLICY_ORIGIN_TYPES,
29
+ } from '../../product-shell/contracts/chat-request-approval-policy.js';
26
30
 
27
31
  const INTERNAL_REQUESTER_SESSION_KEY_PARAM = '__claworldRequesterSessionKey';
28
32
 
@@ -348,20 +352,51 @@ function projectToolManageWorldActionResponse(payload = {}, { accountId = null,
348
352
  };
349
353
  }
350
354
 
351
- const PROFILE_ACTIONS = Object.freeze([
355
+ const CHAT_INBOX_ACTIONS = Object.freeze([
356
+ 'list',
357
+ 'accept',
358
+ 'reject',
359
+ ]);
360
+
361
+ function normalizeChatInboxAction(value, fallback = null) {
362
+ const normalized = normalizeText(value, fallback);
363
+ return CHAT_INBOX_ACTIONS.includes(normalized) ? normalized : fallback;
364
+ }
365
+
366
+ function inferChatInboxAction(params = {}) {
367
+ return normalizeChatInboxAction(params.action, 'list');
368
+ }
369
+
370
+ function projectToolChatInboxActionResponse(payload = {}, { accountId = null, action = 'list' } = {}) {
371
+ const resolvedAction = normalizeChatInboxAction(action, 'list');
372
+ if (resolvedAction === 'list') {
373
+ return {
374
+ action: resolvedAction,
375
+ ...projectToolChatInboxResponse(payload, { accountId }),
376
+ };
377
+ }
378
+ return {
379
+ action: resolvedAction,
380
+ ...projectToolChatRequestMutationResponse(payload, { accountId }),
381
+ };
382
+ }
383
+
384
+ const ACCOUNT_ACTIONS = Object.freeze([
352
385
  'view',
353
386
  'update_identity',
387
+ 'update_chat_policy',
354
388
  ]);
355
389
 
356
- function normalizeProfileAction(value, fallback = null) {
390
+ function normalizeAccountAction(value, fallback = null) {
357
391
  const normalized = normalizeText(value, fallback);
358
- return PROFILE_ACTIONS.includes(normalized) ? normalized : fallback;
392
+ return ACCOUNT_ACTIONS.includes(normalized) ? normalized : fallback;
359
393
  }
360
394
 
361
- function inferProfileAction(params = {}) {
362
- const explicitAction = normalizeProfileAction(params.action, null);
395
+ function inferAccountAction(params = {}) {
396
+ const explicitAction = normalizeAccountAction(params.action, null);
363
397
  if (explicitAction) return explicitAction;
364
398
  if (normalizeText(params.displayName, null)) return 'update_identity';
399
+ if (normalizeObject(params.chatRequestApprovalPolicy, null)) return 'update_chat_policy';
365
400
  return 'view';
366
401
  }
367
402
 
@@ -420,34 +455,118 @@ function projectToolShareCard(payload = null) {
420
455
  };
421
456
  }
422
457
 
423
- function projectToolProfileResponse({
424
- action = 'view',
458
+ function projectToolAccountIdentityFields(identityPayload = null) {
459
+ const projectedIdentity = projectToolPublicIdentity(identityPayload);
460
+ if (projectedIdentity) {
461
+ return {
462
+ publicIdentity: projectedIdentity.publicIdentity,
463
+ recommendedDisplayName: projectedIdentity.recommendedDisplayName,
464
+ requiredAction: projectedIdentity.requiredAction,
465
+ nextAction: projectedIdentity.nextAction,
466
+ nextTool: projectedIdentity.nextTool,
467
+ missingFields: projectedIdentity.missingFields,
468
+ feedbackSummary: projectedIdentity.feedbackSummary,
469
+ };
470
+ }
471
+ return {
472
+ publicIdentity: null,
473
+ recommendedDisplayName: null,
474
+ requiredAction: null,
475
+ nextAction: null,
476
+ nextTool: null,
477
+ missingFields: [],
478
+ feedbackSummary: null,
479
+ };
480
+ }
481
+
482
+ function projectToolChatRequestApprovalPolicy(payload = null) {
483
+ const policy = normalizeObject(payload, null);
484
+ if (!policy) return null;
485
+ return {
486
+ agentId: normalizeText(policy.agentId, null),
487
+ schemaVersion: Number.isInteger(policy.schemaVersion) ? policy.schemaVersion : null,
488
+ syncedAt: normalizeText(policy.syncedAt, null),
489
+ credentialId: normalizeText(policy.credentialId, null),
490
+ source: normalizeObject(policy.source, {})
491
+ ? {
492
+ channel: normalizeText(policy.source?.channel, null),
493
+ integration: normalizeText(policy.source?.integration, null),
494
+ accountId: normalizeText(policy.source?.accountId, null),
495
+ }
496
+ : {},
497
+ policy: normalizeObject(policy.policy, {})
498
+ ? {
499
+ mode: normalizeText(policy.policy?.mode, null),
500
+ blocks: {
501
+ originTypes: Array.isArray(policy.policy?.blocks?.originTypes) ? policy.policy.blocks.originTypes : [],
502
+ worldIds: Array.isArray(policy.policy?.blocks?.worldIds) ? policy.policy.blocks.worldIds : [],
503
+ },
504
+ }
505
+ : null,
506
+ };
507
+ }
508
+
509
+ function projectToolAccountViewResponse({
510
+ accountId = null,
511
+ pairingPayload = null,
512
+ identityPayload = null,
513
+ } = {}) {
514
+ const identityReady = identityPayload?.ready === true;
515
+ const ready = pairingPayload?.status === 'paired' && identityReady;
516
+ const resolvedShareCard = identityPayload && Object.prototype.hasOwnProperty.call(identityPayload, 'shareCard')
517
+ ? projectToolShareCard(identityPayload.shareCard)
518
+ : undefined;
519
+ return {
520
+ action: 'view',
521
+ status: ready ? 'ready' : 'pending',
522
+ ready,
523
+ readiness: pairingPayload?.status === 'paired'
524
+ ? (identityReady ? 'paired_and_ready' : 'paired_but_identity_pending')
525
+ : 'installed_unactivated',
526
+ accountId: normalizeText(pairingPayload?.runtimeConfig?.accountId, normalizeText(accountId, null)),
527
+ reason: normalizeText(pairingPayload?.reason, null),
528
+ bindingSource: normalizeText(pairingPayload?.bindingSource, null),
529
+ activation: {
530
+ status: pairingPayload?.status === 'paired' ? 'ready' : 'pending',
531
+ },
532
+ relay: {
533
+ agentId: normalizeText(
534
+ pairingPayload?.runtimeConfig?.relay?.agentId,
535
+ normalizeText(pairingPayload?.relayAgent?.agentId, null),
536
+ ),
537
+ displayName: normalizeText(pairingPayload?.relayAgent?.displayName, null),
538
+ discoverable: pairingPayload?.relayAgent?.discoverable ?? null,
539
+ contactable: pairingPayload?.relayAgent?.contactable ?? null,
540
+ online: pairingPayload?.relayAgent?.online ?? null,
541
+ resolved: pairingPayload?.relayAgent?.resolved ?? null,
542
+ bindingStatus: pairingPayload?.status === 'paired' ? 'bound' : 'unactivated',
543
+ },
544
+ ...projectToolAccountIdentityFields(identityPayload),
545
+ chatRequestApprovalPolicy: projectToolChatRequestApprovalPolicy(identityPayload?.chatRequestApprovalPolicy),
546
+ ...(resolvedShareCard !== undefined ? { shareCard: resolvedShareCard } : {}),
547
+ };
548
+ }
549
+
550
+ function projectToolAccountMutationResponse({
551
+ action = 'update_identity',
425
552
  accountId = null,
426
553
  identityPayload = null,
427
554
  shareCard = undefined,
428
555
  runtimeActivation = null,
429
556
  } = {}) {
430
- const projectedIdentity = projectToolPublicIdentity(identityPayload);
431
557
  const resolvedShareCard = shareCard !== undefined
432
558
  ? shareCard
433
559
  : (identityPayload && Object.prototype.hasOwnProperty.call(identityPayload, 'shareCard')
434
560
  ? projectToolShareCard(identityPayload.shareCard)
435
561
  : undefined);
436
- const ready = projectedIdentity?.ready === true;
562
+ const ready = identityPayload?.ready === true;
437
563
  return {
438
564
  action,
439
565
  status: ready ? 'ready' : 'pending',
440
566
  ready,
441
567
  accountId: normalizeText(accountId, null),
442
- ...(projectedIdentity || {
443
- publicIdentity: null,
444
- recommendedDisplayName: null,
445
- requiredAction: null,
446
- nextAction: null,
447
- nextTool: null,
448
- missingFields: [],
449
- feedbackSummary: null,
450
- }),
568
+ ...projectToolAccountIdentityFields(identityPayload),
569
+ chatRequestApprovalPolicy: projectToolChatRequestApprovalPolicy(identityPayload?.chatRequestApprovalPolicy),
451
570
  ...(resolvedShareCard !== undefined ? { shareCard: resolvedShareCard } : {}),
452
571
  ...(runtimeActivation ? { runtimeActivation } : {}),
453
572
  ...(action === 'update_identity'
@@ -456,6 +575,10 @@ function projectToolProfileResponse({
456
575
  ? ['publicIdentity', 'shareCard']
457
576
  : ['publicIdentity'],
458
577
  }
578
+ : action === 'update_chat_policy'
579
+ ? {
580
+ updated: ['chatRequestApprovalPolicy'],
581
+ }
459
582
  : {}),
460
583
  };
461
584
  }
@@ -466,6 +589,43 @@ function buildRegisteredTools(api, plugin) {
466
589
  minLength: 1,
467
590
  examples: ['claworld'],
468
591
  });
592
+ const chatRequestApprovalPolicyProperty = objectParam({
593
+ description: 'Backend-managed inbound chat-request policy for this account.',
594
+ required: ['mode'],
595
+ properties: {
596
+ mode: stringParam({
597
+ description: 'Policy mode controlling which new inbound chat requests auto-accept.',
598
+ enumValues: CHAT_REQUEST_APPROVAL_POLICY_MODES,
599
+ examples: ['open', 'manual_review'],
600
+ }),
601
+ blocks: objectParam({
602
+ description: 'Optional deny rules applied before the allow mode is evaluated.',
603
+ properties: {
604
+ originTypes: arrayParam({
605
+ description: 'Canonical request origin types that should always be rejected.',
606
+ items: stringParam({
607
+ enumValues: CHAT_REQUEST_APPROVAL_POLICY_ORIGIN_TYPES,
608
+ }),
609
+ examples: [['world_broadcast']],
610
+ }),
611
+ worldIds: arrayParam({
612
+ description: 'World ids that should always be rejected.',
613
+ items: stringParam({}),
614
+ examples: [['dating-demo-world']],
615
+ }),
616
+ },
617
+ }),
618
+ },
619
+ examples: [
620
+ {
621
+ mode: 'trusted_or_world',
622
+ blocks: {
623
+ originTypes: ['world_broadcast'],
624
+ worldIds: [],
625
+ },
626
+ },
627
+ ],
628
+ });
469
629
  const worldIdProperty = stringParam({
470
630
  description: 'Canonical world id returned by claworld_list_worlds or claworld_get_world_detail.',
471
631
  minLength: 1,
@@ -485,7 +645,7 @@ function buildRegisteredTools(api, plugin) {
485
645
  metadata: buildToolMetadata({
486
646
  category: 'world_discovery',
487
647
  usageNotes: [
488
- 'Use after claworld_pair_agent when the user wants to browse worlds.',
648
+ 'Use after claworld_account(action=view) when the user wants to browse worlds.',
489
649
  'After the user picks one world, call claworld_get_world_detail.',
490
650
  ],
491
651
  examples: [
@@ -908,82 +1068,55 @@ function buildRegisteredTools(api, plugin) {
908
1068
  {
909
1069
  name: 'claworld_chat_inbox',
910
1070
  label: 'Claworld Chat Inbox',
911
- description: 'Canonical chat inbox tool. Review pending requests plus current or recent Claworld chats and the local session references you can use to check progress.',
1071
+ description: 'Canonical chat inbox tool. List pending requests plus current or recent Claworld chats and the local session references you can use to check progress, or accept/reject one inbox request from the same surface.',
912
1072
  metadata: buildToolMetadata({
913
1073
  category: 'chat_request',
914
1074
  usageNotes: [
915
- 'Use to review pending inbound requests waiting for acceptance.',
1075
+ 'Default action is list. Use it to review pending inbound requests waiting for acceptance.',
916
1076
  'Use to locate the relevant Claworld chat and the local sessionKey tied to it.',
917
1077
  'If the user asks about one chat, first locate it here, then use your local session-send tool to ask that local session for a progress update or short summary.',
918
1078
  'Prefer asking the local chat session for a concise update before inspecting raw local transcript details.',
919
1079
  'Use direction=outbound when focusing on chats you initiated.',
1080
+ 'After action=accept or action=reject, call action=list again to refresh the inbox view.',
920
1081
  ],
921
1082
  examples: [
922
1083
  {
923
1084
  title: 'Review inbound chat state',
924
1085
  input: {
925
1086
  accountId: 'claworld',
1087
+ action: 'list',
926
1088
  direction: 'inbound',
927
1089
  },
928
1090
  outcome: 'Returns pending requests plus related chats for the current account.',
929
1091
  },
930
- ],
931
- }),
932
- parameters: objectParam({
933
- description: 'Review overall Claworld chat state for the current account before deciding whether to accept a request or query one local chat session for progress.',
934
- required: ['accountId'],
935
- properties: {
936
- accountId: accountIdProperty,
937
- direction: stringParam({
938
- description: 'Filter to inbound or outbound chat state from the current account perspective.',
939
- enumValues: ['inbound', 'outbound'],
940
- examples: ['inbound'],
941
- }),
942
- },
943
- examples: [
944
- {
945
- accountId: 'claworld',
946
- direction: 'inbound',
947
- },
948
- ],
949
- }),
950
- async execute(_toolCallId, params = {}) {
951
- const context = await resolveToolContext(api, plugin, params);
952
- const payload = await plugin.helpers.social.listChatInbox({
953
- ...context,
954
- direction: params.direction || null,
955
- });
956
- return buildToolResult(projectToolChatInboxResponse(payload, { accountId: context.accountId }));
957
- },
958
- },
959
- {
960
- name: 'claworld_accept_chat_request',
961
- label: 'Claworld Accept Chat Request',
962
- description: 'Canonical approval tool for one inbound chat request. After acceptance, the backend prepares kickoff and the runtime owns the live session.',
963
- metadata: buildToolMetadata({
964
- category: 'chat_request',
965
- usageNotes: [
966
- 'Use the chatRequestId returned by claworld_chat_inbox pendingRequests.',
967
- 'After acceptance, do not try to send a separate raw message tool call; wait for runtime-owned live conversation.',
968
- ],
969
- examples: [
970
1092
  {
971
- title: 'Accept one inbound request',
1093
+ title: 'Accept one inbound request from the inbox',
972
1094
  input: {
973
1095
  accountId: 'claworld',
1096
+ action: 'accept',
974
1097
  chatRequestId: 'req_demo_1',
975
1098
  },
976
- outcome: 'Marks the request accepted and returns kickoff progress.',
1099
+ outcome: 'Marks the request accepted and returns kickoff progress from the same inbox surface.',
977
1100
  },
978
1101
  ],
979
1102
  }),
980
1103
  parameters: objectParam({
981
- description: 'Accept one inbound chat request for the current account.',
982
- required: ['accountId', 'chatRequestId'],
1104
+ description: 'List inbox state, or accept/reject one inbox request for the current account.',
1105
+ required: ['accountId'],
983
1106
  properties: {
984
1107
  accountId: accountIdProperty,
1108
+ action: stringParam({
1109
+ description: 'Inbox action. Defaults to list. Use accept or reject to decide one pending inbox request.',
1110
+ enumValues: CHAT_INBOX_ACTIONS,
1111
+ examples: ['list', 'accept', 'reject'],
1112
+ }),
1113
+ direction: stringParam({
1114
+ description: 'Filter to inbound or outbound chat state from the current account perspective. Used with action=list.',
1115
+ enumValues: ['inbound', 'outbound'],
1116
+ examples: ['inbound'],
1117
+ }),
985
1118
  chatRequestId: stringParam({
986
- description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests.',
1119
+ description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests. Required for action=accept or action=reject.',
987
1120
  minLength: 1,
988
1121
  examples: ['req_demo_1'],
989
1122
  }),
@@ -991,65 +1124,46 @@ function buildRegisteredTools(api, plugin) {
991
1124
  examples: [
992
1125
  {
993
1126
  accountId: 'claworld',
994
- chatRequestId: 'req_demo_1',
995
- },
996
- ],
997
- }),
998
- async execute(_toolCallId, params = {}) {
999
- const context = await resolveToolContext(api, plugin, params);
1000
- const payload = await plugin.helpers.social.acceptChatRequest({
1001
- ...context,
1002
- chatRequestId: params.chatRequestId,
1003
- });
1004
- return buildToolResult(projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }));
1005
- },
1006
- },
1007
- {
1008
- name: 'claworld_reject_chat_request',
1009
- label: 'Claworld Reject Chat Request',
1010
- description: 'Canonical rejection tool for one inbound chat request. Use this when the current account explicitly declines the request instead of accepting it.',
1011
- metadata: buildToolMetadata({
1012
- category: 'chat_request',
1013
- usageNotes: [
1014
- 'Use the chatRequestId returned by claworld_list_chat_requests.',
1015
- 'Use only for inbound requests that the current account wants to reject.',
1016
- ],
1017
- examples: [
1018
- {
1019
- title: 'Reject one inbound request',
1020
- input: {
1021
- accountId: 'claworld',
1022
- chatRequestId: 'req_demo_1',
1023
- },
1024
- outcome: 'Marks the request rejected and returns the closed request projection.',
1127
+ action: 'list',
1128
+ direction: 'inbound',
1025
1129
  },
1026
- ],
1027
- }),
1028
- parameters: objectParam({
1029
- description: 'Reject one inbound chat request for the current account.',
1030
- required: ['accountId', 'chatRequestId'],
1031
- properties: {
1032
- accountId: accountIdProperty,
1033
- chatRequestId: stringParam({
1034
- description: 'Canonical chat request id returned by claworld_list_chat_requests.',
1035
- minLength: 1,
1036
- examples: ['req_demo_1'],
1037
- }),
1038
- },
1039
- examples: [
1040
1130
  {
1041
1131
  accountId: 'claworld',
1132
+ action: 'accept',
1042
1133
  chatRequestId: 'req_demo_1',
1043
1134
  },
1044
1135
  ],
1045
1136
  }),
1046
1137
  async execute(_toolCallId, params = {}) {
1047
1138
  const context = await resolveToolContext(api, plugin, params);
1048
- const payload = await plugin.helpers.social.rejectChatRequest({
1139
+ const action = inferChatInboxAction(params);
1140
+ if (action === 'accept' || action === 'reject') {
1141
+ const chatRequestId = normalizeText(params.chatRequestId, null);
1142
+ if (!chatRequestId) {
1143
+ requireManageWorldField('chatRequestId', `chatRequestId is required for action=${action}`);
1144
+ }
1145
+ const payload = action === 'accept'
1146
+ ? await plugin.helpers.social.acceptChatRequest({
1147
+ ...context,
1148
+ chatRequestId,
1149
+ })
1150
+ : await plugin.helpers.social.rejectChatRequest({
1151
+ ...context,
1152
+ chatRequestId,
1153
+ });
1154
+ return buildToolResult(projectToolChatInboxActionResponse(payload, {
1155
+ accountId: context.accountId,
1156
+ action,
1157
+ }));
1158
+ }
1159
+ const payload = await plugin.helpers.social.listChatInbox({
1049
1160
  ...context,
1050
- chatRequestId: params.chatRequestId,
1161
+ direction: params.direction || null,
1051
1162
  });
1052
- return buildToolResult(projectToolChatRequestMutationResponse(payload, { accountId: context.accountId }));
1163
+ return buildToolResult(projectToolChatInboxActionResponse(payload, {
1164
+ accountId: context.accountId,
1165
+ action,
1166
+ }));
1053
1167
  },
1054
1168
  },
1055
1169
  {
@@ -1210,123 +1324,24 @@ function buildRegisteredTools(api, plugin) {
1210
1324
  },
1211
1325
  },
1212
1326
  {
1213
- name: 'claworld_pair_agent',
1214
- label: 'Claworld Pair Agent',
1215
- description: 'Bootstrap and diagnostics tool. Ensure the current Claworld account resolves to a usable relay binding before world discovery or request flows.',
1216
- metadata: buildToolMetadata({
1217
- category: 'bootstrap',
1218
- usageNotes: [
1219
- 'Run once after install or when channel binding looks unhealthy.',
1220
- 'Use before any world or chat-request flow if the current account has not been validated yet.',
1221
- ],
1222
- examples: [
1223
- {
1224
- title: 'Validate the managed account binding',
1225
- input: {
1226
- accountId: 'claworld',
1227
- },
1228
- outcome: 'Returns the resolved relay identity and binding source.',
1229
- },
1230
- ],
1231
- }),
1232
- parameters: objectParam({
1233
- description: 'Validate or bootstrap the relay binding for one Claworld account.',
1234
- required: ['accountId'],
1235
- properties: {
1236
- accountId: accountIdProperty,
1237
- },
1238
- examples: [
1239
- {
1240
- accountId: 'claworld',
1241
- },
1242
- ],
1243
- }),
1244
- async execute(_toolCallId, params = {}) {
1245
- const cfg = await loadCurrentConfig(api);
1246
- const accountId = normalizeText(params.accountId, plugin.config.defaultAccountId(cfg) || null);
1247
- const runtimeConfig = plugin.config.resolveRuntimeConfig(cfg, accountId);
1248
- const payload = await plugin.helpers.pairing.ensureAgentPairing({
1249
- cfg,
1250
- accountId,
1251
- runtimeConfig,
1252
- });
1253
- const pairedAgentId = payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null;
1254
- const publicIdentity = await plugin.runtime.productShell.profile.getPublicIdentity({
1255
- cfg,
1256
- accountId,
1257
- runtimeConfig: payload.runtimeConfig || runtimeConfig,
1258
- agentId: pairedAgentId,
1259
- });
1260
- const ready = payload.status === 'paired' && publicIdentity?.ready === true;
1261
- const readiness = payload.status === 'paired'
1262
- ? (publicIdentity?.ready === true ? 'paired_and_ready' : 'paired_but_identity_pending')
1263
- : 'installed_unactivated';
1264
- return buildToolResult({
1265
- status: ready ? 'ready' : 'pending',
1266
- ready,
1267
- readiness,
1268
- reason: payload.reason || null,
1269
- requiredAction: publicIdentity?.requiredAction || (ready ? null : 'set_public_identity'),
1270
- nextAction: publicIdentity?.nextAction || (ready ? 'continue_claworld_flow' : 'set_public_identity'),
1271
- nextTool: publicIdentity?.nextTool || (ready ? null : 'claworld_profile'),
1272
- missingFields: Array.isArray(publicIdentity?.missingFields) ? publicIdentity.missingFields : [],
1273
- accountId: payload.runtimeConfig?.accountId || accountId,
1274
- bindingSource: payload.bindingSource || null,
1275
- activation: {
1276
- status: payload.status === 'paired' ? 'ready' : 'pending',
1277
- },
1278
- relay: {
1279
- agentId: payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null,
1280
- displayName: payload.relayAgent?.displayName || null,
1281
- discoverable: payload.relayAgent?.discoverable ?? null,
1282
- contactable: payload.relayAgent?.contactable ?? null,
1283
- online: payload.relayAgent?.online ?? null,
1284
- resolved: payload.relayAgent?.resolved ?? null,
1285
- bindingStatus: payload.status === 'paired' ? 'bound' : 'unactivated',
1286
- },
1287
- publicIdentity: publicIdentity
1288
- ? {
1289
- status: publicIdentity.status || null,
1290
- ready: publicIdentity.ready ?? null,
1291
- displayIdentity: publicIdentity.publicIdentity?.displayIdentity || null,
1292
- displayName: publicIdentity.publicIdentity?.displayName || null,
1293
- code: publicIdentity.publicIdentity?.code || null,
1294
- nextAction: publicIdentity.nextAction || null,
1295
- nextTool: publicIdentity.nextTool || null,
1296
- missingFields: Array.isArray(publicIdentity.missingFields) ? publicIdentity.missingFields : [],
1297
- recommendedDisplayName: publicIdentity.recommendedDisplayName || null,
1298
- feedbackSummary: publicIdentity.feedbackSummary && typeof publicIdentity.feedbackSummary === 'object'
1299
- ? {
1300
- totalLikesReceived: Number(publicIdentity.feedbackSummary.totalLikesReceived || 0),
1301
- totalDislikesReceived: Number(publicIdentity.feedbackSummary.totalDislikesReceived || 0),
1302
- totalLikesGiven: Number(publicIdentity.feedbackSummary.totalLikesGiven || 0),
1303
- totalDislikesGiven: Number(publicIdentity.feedbackSummary.totalDislikesGiven || 0),
1304
- }
1305
- : null,
1306
- }
1307
- : null,
1308
- });
1309
- },
1310
- },
1311
- {
1312
- name: 'claworld_profile',
1313
- label: 'Claworld Profile',
1314
- description: 'View or update the paired Claworld public profile. This surface covers public identity readiness and, when requested, generates a temporary public identity card for sharing.',
1327
+ name: 'claworld_account',
1328
+ label: 'Claworld Account',
1329
+ description: 'Canonical account surface. View current relay binding plus public identity readiness, or update the public display identity for the current Claworld account.',
1315
1330
  metadata: buildToolMetadata({
1316
- category: 'profile',
1331
+ category: 'account',
1317
1332
  usageNotes: [
1318
- 'Default action is view; omit action to inspect the current public identity state.',
1333
+ 'Default action is view. It runs the readiness/binding check and returns the current public identity state.',
1319
1334
  'Use action=update_identity after the user confirms a public-facing display name.',
1320
1335
  'Set generateShareCard=true to return a temporary public identity card URL.',
1321
1336
  ],
1322
1337
  examples: [
1323
1338
  {
1324
- title: 'View the current profile state',
1339
+ title: 'View the current account state',
1325
1340
  input: {
1326
1341
  accountId: 'claworld',
1327
1342
  action: 'view',
1328
1343
  },
1329
- outcome: 'Returns the current public identity and readiness state.',
1344
+ outcome: 'Returns readiness, relay binding, and public identity for the current account.',
1330
1345
  },
1331
1346
  {
1332
1347
  title: 'Update public identity and return a share card',
@@ -1338,23 +1353,38 @@ function buildRegisteredTools(api, plugin) {
1338
1353
  },
1339
1354
  outcome: 'Persists the display name, keeps the stable code, and returns a temporary share-card URL.',
1340
1355
  },
1356
+ {
1357
+ title: 'Update the inbound chat policy',
1358
+ input: {
1359
+ accountId: 'claworld',
1360
+ action: 'update_chat_policy',
1361
+ chatRequestApprovalPolicy: {
1362
+ mode: 'trusted_or_world',
1363
+ blocks: {
1364
+ originTypes: ['world_broadcast'],
1365
+ },
1366
+ },
1367
+ },
1368
+ outcome: 'Stores the account-level chat-request policy in the backend and returns the updated policy snapshot.',
1369
+ },
1341
1370
  ],
1342
1371
  }),
1343
1372
  parameters: objectParam({
1344
- description: 'View or update the public profile for one Claworld account.',
1373
+ description: 'View or update the current Claworld account state.',
1345
1374
  required: ['accountId'],
1346
1375
  properties: {
1347
1376
  accountId: accountIdProperty,
1348
1377
  action: stringParam({
1349
- description: 'Profile action. Defaults to view; inferred as update_identity when displayName is present.',
1350
- enumValues: PROFILE_ACTIONS,
1351
- examples: ['view', 'update_identity'],
1378
+ description: 'Account action. Defaults to view; inferred from displayName or chatRequestApprovalPolicy when omitted.',
1379
+ enumValues: ACCOUNT_ACTIONS,
1380
+ examples: ['view', 'update_identity', 'update_chat_policy'],
1352
1381
  }),
1353
1382
  displayName: stringParam({
1354
1383
  description: 'Public-facing display name. Required for action=update_identity. # is reserved and must not appear here.',
1355
1384
  minLength: 1,
1356
1385
  examples: ['Moza', '小发发'],
1357
1386
  }),
1387
+ chatRequestApprovalPolicy: chatRequestApprovalPolicyProperty,
1358
1388
  generateShareCard: booleanParam({
1359
1389
  description: 'When true, return a temporary public identity card URL. Defaults to false for view and true for update_identity.',
1360
1390
  }),
@@ -1375,16 +1405,23 @@ function buildRegisteredTools(api, plugin) {
1375
1405
  displayName: '小发发',
1376
1406
  generateShareCard: true,
1377
1407
  },
1408
+ {
1409
+ accountId: 'claworld',
1410
+ action: 'update_chat_policy',
1411
+ chatRequestApprovalPolicy: {
1412
+ mode: 'manual_review',
1413
+ },
1414
+ },
1378
1415
  ],
1379
1416
  }),
1380
1417
  async execute(_toolCallId, params = {}) {
1381
- const context = await resolveToolContext(api, plugin, params, { bindRuntime: false });
1382
- const action = inferProfileAction(params);
1418
+ const action = inferAccountAction(params);
1383
1419
  const generateShareCard = typeof params.generateShareCard === 'boolean'
1384
1420
  ? params.generateShareCard
1385
1421
  : action === 'update_identity';
1386
1422
 
1387
1423
  if (action === 'update_identity') {
1424
+ const context = await resolveToolContext(api, plugin, params, { bindRuntime: false });
1388
1425
  const displayName = normalizeText(params.displayName, null);
1389
1426
  if (!displayName) {
1390
1427
  requireManageWorldField('displayName', 'displayName is required for action=update_identity');
@@ -1395,7 +1432,7 @@ function buildRegisteredTools(api, plugin) {
1395
1432
  generateShareCard,
1396
1433
  expiresInSeconds: params.expiresInSeconds ?? null,
1397
1434
  });
1398
- return buildToolResult(projectToolProfileResponse({
1435
+ return buildToolResult(projectToolAccountMutationResponse({
1399
1436
  action,
1400
1437
  accountId: context.accountId,
1401
1438
  identityPayload: payload,
@@ -1403,15 +1440,47 @@ function buildRegisteredTools(api, plugin) {
1403
1440
  }));
1404
1441
  }
1405
1442
 
1406
- const payload = await plugin.runtime.productShell.profile.getPublicIdentity({
1407
- ...context,
1443
+ if (action === 'update_chat_policy') {
1444
+ const context = await resolveToolContext(api, plugin, params);
1445
+ const chatRequestApprovalPolicy = normalizeObject(params.chatRequestApprovalPolicy, null);
1446
+ if (!chatRequestApprovalPolicy) {
1447
+ requireManageWorldField(
1448
+ 'chatRequestApprovalPolicy',
1449
+ 'chatRequestApprovalPolicy is required for action=update_chat_policy',
1450
+ );
1451
+ }
1452
+ const payload = await plugin.runtime.productShell.profile.updateChatRequestApprovalPolicy({
1453
+ ...context,
1454
+ chatRequestApprovalPolicy,
1455
+ });
1456
+ return buildToolResult(projectToolAccountMutationResponse({
1457
+ action,
1458
+ accountId: context.accountId,
1459
+ identityPayload: payload,
1460
+ }));
1461
+ }
1462
+
1463
+ const cfg = await loadCurrentConfig(api);
1464
+ const accountId = normalizeText(params.accountId, plugin.config.defaultAccountId(cfg) || null);
1465
+ const runtimeConfig = plugin.config.resolveRuntimeConfig(cfg, accountId);
1466
+ const pairingPayload = await plugin.helpers.pairing.ensureAgentPairing({
1467
+ cfg,
1468
+ accountId,
1469
+ runtimeConfig,
1470
+ });
1471
+ const pairedAgentId = pairingPayload.runtimeConfig?.relay?.agentId || pairingPayload.relayAgent?.agentId || null;
1472
+ const identityPayload = await plugin.runtime.productShell.profile.getPublicIdentity({
1473
+ cfg,
1474
+ accountId,
1475
+ runtimeConfig: pairingPayload.runtimeConfig || runtimeConfig,
1476
+ agentId: pairedAgentId,
1408
1477
  generateShareCard,
1409
1478
  expiresInSeconds: params.expiresInSeconds ?? null,
1410
1479
  });
1411
- return buildToolResult(projectToolProfileResponse({
1412
- action,
1413
- accountId: context.accountId,
1414
- identityPayload: payload,
1480
+ return buildToolResult(projectToolAccountViewResponse({
1481
+ accountId,
1482
+ pairingPayload,
1483
+ identityPayload,
1415
1484
  }));
1416
1485
  },
1417
1486
  },