@xfxstudio/claworld 0.2.8 → 0.2.10-beta.0

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 (50) hide show
  1. package/README.md +1 -1
  2. package/openclaw.plugin.json +7 -63
  3. package/package.json +6 -2
  4. package/skills/claworld-help/SKILL.md +7 -3
  5. package/skills/claworld-join-and-chat/SKILL.md +38 -9
  6. package/skills/claworld-manage-worlds/SKILL.md +81 -10
  7. package/src/lib/agent-profile.js +8 -3
  8. package/src/lib/chat-request.js +19 -1
  9. package/src/lib/policy.js +2 -6
  10. package/src/lib/public-identity.js +175 -0
  11. package/src/lib/relay/kickoff-text.js +7 -1
  12. package/src/openclaw/installer/cli.js +46 -1
  13. package/src/openclaw/installer/constants.js +1 -0
  14. package/src/openclaw/installer/core.js +234 -3
  15. package/src/openclaw/installer/doctor.js +2 -2
  16. package/src/openclaw/plugin/account-identity.js +1 -2
  17. package/src/openclaw/plugin/claworld-channel-plugin.js +302 -266
  18. package/src/openclaw/plugin/config-schema.js +9 -23
  19. package/src/openclaw/plugin/managed-config.js +284 -79
  20. package/src/openclaw/plugin/onboarding.js +22 -42
  21. package/src/openclaw/plugin/register.js +144 -25
  22. package/src/openclaw/plugin/relay-client.js +237 -18
  23. package/src/openclaw/runtime/backend-error-context.js +91 -0
  24. package/src/openclaw/runtime/feedback-helper.js +1 -2
  25. package/src/openclaw/runtime/product-shell-helper.js +43 -9
  26. package/src/openclaw/runtime/tool-contracts.js +65 -3
  27. package/src/openclaw/runtime/tool-inventory.js +8 -1
  28. package/src/openclaw/runtime/world-moderation-helper.js +3 -19
  29. package/src/product-shell/contracts/candidate-feed.js +7 -0
  30. package/src/product-shell/contracts/world-manifest.js +0 -1
  31. package/src/product-shell/contracts/world-orchestration.js +10 -1
  32. package/src/product-shell/conversation-feedback/conversation-feedback-service.js +261 -0
  33. package/src/product-shell/feedback/feedback-routes.js +0 -1
  34. package/src/product-shell/feedback/feedback-service.js +4 -9
  35. package/src/product-shell/index.js +40 -7
  36. package/src/product-shell/matching/matchmaking-service.js +22 -1
  37. package/src/product-shell/membership/membership-service.js +5 -1
  38. package/src/product-shell/onboarding/onboarding-service.js +10 -21
  39. package/src/product-shell/profile/public-identity-routes.js +60 -0
  40. package/src/product-shell/profile/public-identity-service.js +190 -0
  41. package/src/product-shell/search/search-service.js +9 -2
  42. package/src/product-shell/social/chat-request-routes.js +4 -1
  43. package/src/product-shell/social/chat-request-service.js +184 -22
  44. package/src/product-shell/social/friend-routes.js +1 -1
  45. package/src/product-shell/social/friend-service.js +16 -19
  46. package/src/product-shell/social/social-routes.js +2 -2
  47. package/src/product-shell/social/social-service.js +31 -35
  48. package/src/product-shell/worlds/world-admin-service.js +31 -10
  49. package/src/product-shell/worlds/world-broadcast-service.js +2 -2
  50. package/src/lib/agent-address.js +0 -46
@@ -7,27 +7,16 @@ import {
7
7
  resolveClaworldManagedRuntimeOptions,
8
8
  } from './managed-config.js';
9
9
  import {
10
- LOCAL_AGENT_BOOTSTRAP_SCHEMA,
11
10
  defaultClaworldAccountId,
12
11
  inspectClaworldChannelAccount,
13
12
  listClaworldAccountIds,
14
13
  } from './config-schema.js';
15
- import { parseAgentHandle } from '../../lib/agent-address.js';
16
14
  import {
17
15
  buildManagedOnboardingStatus as buildClaworldOnboardingStatus,
18
16
  inspectManagedClaworldInstall,
19
17
  seedManagedWorkspace as ensureManagedWorkspaceSeed,
20
18
  } from '../installer/core.js';
21
19
 
22
- const LOCAL_AGENT_CODE_REGEX = new RegExp(
23
- LOCAL_AGENT_BOOTSTRAP_SCHEMA?.properties?.agentCode?.pattern || '^[A-Za-z0-9._:+~-]+$',
24
- 'i',
25
- );
26
-
27
- function isCanonicalAgentHandle(value) {
28
- return Boolean(parseAgentHandle(value)?.canonical);
29
- }
30
-
31
20
  function collectUnsupportedSetupFlags(input = {}) {
32
21
  const unsupported = [];
33
22
  const flagMap = [
@@ -69,7 +58,7 @@ function validateClaworldSetupInput({ cfg = {}, accountId = null, input = {} } =
69
58
  const unsupportedFlags = collectUnsupportedSetupFlags(input);
70
59
  if (unsupportedFlags.length > 0) {
71
60
  return (
72
- 'Claworld setup only supports --name, --http-url/--url, --app-token, and --code. ' +
61
+ 'Claworld setup only supports --name, --http-url/--url, and --app-token. ' +
73
62
  `Unsupported flag(s): ${unsupportedFlags.join(', ')}.`
74
63
  );
75
64
  }
@@ -92,24 +81,15 @@ function validateClaworldSetupInput({ cfg = {}, accountId = null, input = {} } =
92
81
  }
93
82
  }
94
83
 
95
- const explicitRegistrationAgentCode = normalizeText(input.code, null);
96
- const existingRegistrationAgentCode = normalizeText(
97
- inspected?.registration?.agentCode,
98
- normalizeText(inspected?.localAgent?.agentCode, null),
84
+ const registrationDisplayName = normalizeText(
85
+ input.name,
86
+ normalizeText(
87
+ inspected?.registration?.displayName,
88
+ normalizeText(inspected?.localAgent?.displayName, null),
89
+ ),
99
90
  );
100
- const registrationAgentCode = explicitRegistrationAgentCode
101
- || (isCanonicalAgentHandle(existingRegistrationAgentCode) ? existingRegistrationAgentCode : null);
102
- if (!appToken && !explicitRegistrationAgentCode && existingRegistrationAgentCode && !isCanonicalAgentHandle(existingRegistrationAgentCode)) {
103
- return 'Existing Claworld registration.agentCode is legacy/raw. Re-run setup with --code <local@namespace> so the namespace stays explicit.';
104
- }
105
- if (!appToken && !registrationAgentCode) {
106
- return 'Claworld identity handle is required unless you already have an appToken. Use --code <local@namespace> or --app-token <token>.';
107
- }
108
- if (!appToken && explicitRegistrationAgentCode && !LOCAL_AGENT_CODE_REGEX.test(explicitRegistrationAgentCode)) {
109
- return 'Claworld identity handle must match ^[A-Za-z0-9._:+~-]+(?:@[A-Za-z0-9._:+~-]+)?$.';
110
- }
111
- if (!appToken && explicitRegistrationAgentCode && !isCanonicalAgentHandle(explicitRegistrationAgentCode)) {
112
- return 'Claworld identity handle must use canonical local@namespace syntax (for example "xiaofafa@robin").';
91
+ if (!appToken && !registrationDisplayName) {
92
+ return 'Claworld public display name is required unless you already have an appToken. Use --name <display-name> or --app-token <token>.';
113
93
  }
114
94
 
115
95
  return null;
@@ -124,12 +104,12 @@ function currentManagedIdentityInput({ cfg = {}, accountId = null } = {}) {
124
104
  };
125
105
  }
126
106
 
127
- const currentCode = normalizeText(
128
- inspected?.registration?.agentCode,
129
- normalizeText(inspected?.localAgent?.agentCode, null),
107
+ const currentDisplayName = normalizeText(
108
+ inspected?.registration?.displayName,
109
+ normalizeText(inspected?.localAgent?.displayName, null),
130
110
  );
131
- return isCanonicalAgentHandle(currentCode)
132
- ? { code: currentCode }
111
+ return currentDisplayName
112
+ ? { name: currentDisplayName }
133
113
  : {};
134
114
  }
135
115
 
@@ -139,18 +119,18 @@ async function collectManagedIdentityInput({ cfg = {}, prompter, accountId = nul
139
119
  return currentInput;
140
120
  }
141
121
 
142
- const code = await prompter.text({
143
- message: 'Choose a unique Claworld identity handle',
144
- initialValue: currentInput.code || '',
145
- placeholder: 'xiaofafa@robin',
122
+ const name = await prompter.text({
123
+ message: 'Choose the public display name to bootstrap this Claworld agent',
124
+ initialValue: currentInput.name || '',
125
+ placeholder: 'Claworld Agent',
146
126
  validate: (value) => {
147
- const message = validateClaworldSetupInput({ input: { code: value } });
127
+ const message = validateClaworldSetupInput({ input: { name: value } });
148
128
  return message || undefined;
149
129
  },
150
130
  });
151
131
 
152
132
  return {
153
- code,
133
+ name,
154
134
  };
155
135
  }
156
136
 
@@ -207,8 +187,8 @@ async function applyManagedOnboardingConfig({
207
187
  const noteLines = [
208
188
  `Bound local agent/account: ${managedOptions.agentId}`,
209
189
  `Remote backend: ${managedOptions.serverUrl}`,
210
- managedOptions.registrationAgentCode
211
- ? `Bootstrap mode: registration (${managedOptions.registrationAgentCode})`
190
+ managedOptions.registrationDisplayName
191
+ ? `Bootstrap mode: registration (${managedOptions.registrationDisplayName})`
212
192
  : 'Bootstrap mode: appToken/manual binding',
213
193
  managedOptions.manageWorkspace
214
194
  ? 'This flow refreshes plugin-side config and the dedicated claworld workspace contract. It does not start a backend service.'
@@ -1,6 +1,6 @@
1
1
  import { createClaworldChannelPlugin } from './claworld-channel-plugin.js';
2
2
  import {
3
- projectToolChatRequestListResponse,
3
+ projectToolChatInboxResponse,
4
4
  projectToolChatRequestMutationResponse,
5
5
  projectToolCreateWorldResponse,
6
6
  projectToolManagedWorldResponse,
@@ -18,6 +18,13 @@ import {
18
18
  logRuntimeBoundary,
19
19
  normalizeRuntimeBoundaryError,
20
20
  } from '../../lib/runtime-errors.js';
21
+ import {
22
+ normalizeBackendFieldError,
23
+ normalizeBackendMissingField,
24
+ normalizeBackendPublicIdentity,
25
+ } from '../runtime/backend-error-context.js';
26
+
27
+ const INTERNAL_REQUESTER_SESSION_KEY_PARAM = '__claworldRequesterSessionKey';
21
28
 
22
29
  function normalizeText(value, fallback = null) {
23
30
  if (value == null) return fallback;
@@ -50,14 +57,30 @@ function buildPublicToolErrorExtras(error) {
50
57
  const backendCode = normalizeText(context.backendCode, null);
51
58
  const backendMessage = normalizeText(context.backendMessage, null);
52
59
  const fieldErrors = Array.isArray(context.fieldErrors)
53
- ? context.fieldErrors.map((fieldError) => normalizePublicFieldError(fieldError)).filter(Boolean)
60
+ ? context.fieldErrors
61
+ .map((fieldError) => normalizeBackendFieldError(fieldError) || normalizePublicFieldError(fieldError))
62
+ .filter(Boolean)
63
+ : [];
64
+ const requiredAction = normalizeText(context.requiredAction, null);
65
+ const nextAction = normalizeText(context.nextAction, null);
66
+ const nextTool = normalizeText(context.nextTool, null);
67
+ const missingFields = Array.isArray(context.missingFields)
68
+ ? context.missingFields
69
+ .map((field) => normalizeBackendMissingField(field))
70
+ .filter(Boolean)
54
71
  : [];
72
+ const publicIdentity = normalizeBackendPublicIdentity(context.publicIdentity);
55
73
 
56
74
  const extra = {
57
75
  ...(Number.isInteger(httpStatus) && httpStatus > 0 ? { httpStatus } : {}),
58
76
  ...(backendCode ? { backendCode } : {}),
59
77
  ...(backendMessage ? { backendMessage } : {}),
60
78
  ...(fieldErrors.length > 0 ? { fieldErrors } : {}),
79
+ ...(requiredAction ? { requiredAction } : {}),
80
+ ...(nextAction ? { nextAction } : {}),
81
+ ...(nextTool ? { nextTool } : {}),
82
+ ...(missingFields.length > 0 ? { missingFields } : {}),
83
+ ...(publicIdentity ? { publicIdentity } : {}),
61
84
  };
62
85
 
63
86
  return Object.keys(extra).length > 0 ? extra : null;
@@ -166,6 +189,7 @@ async function resolveToolContext(api, plugin, params = {}) {
166
189
  accountId,
167
190
  runtimeConfig,
168
191
  agentId: normalizeText(params.agentId, runtimeConfig.relay?.agentId || null),
192
+ requesterSessionKey: normalizeText(params[INTERNAL_REQUESTER_SESSION_KEY_PARAM], null),
169
193
  });
170
194
  }
171
195
 
@@ -175,6 +199,7 @@ async function resolveToolContext(api, plugin, params = {}) {
175
199
  accountId,
176
200
  runtimeConfig,
177
201
  agentId,
202
+ requesterSessionKey: normalizeText(params[INTERNAL_REQUESTER_SESSION_KEY_PARAM], null),
178
203
  };
179
204
  }
180
205
 
@@ -549,7 +574,7 @@ function buildRegisteredTools(api, plugin) {
549
574
  ...context,
550
575
  displayName: params.displayName,
551
576
  worldContextText: params.worldContextText,
552
- enabled: params.enabled === true,
577
+ enabled: typeof params.enabled === 'boolean' ? params.enabled : true,
553
578
  });
554
579
  return buildToolResult(projectToolCreateWorldResponse(payload, { accountId: context.accountId }));
555
580
  },
@@ -704,7 +729,7 @@ function buildRegisteredTools(api, plugin) {
704
729
  category: 'chat_request',
705
730
  usageNotes: [
706
731
  'For world-scoped chat, use the targetAgentId returned by claworld_join_world.',
707
- 'After creation, use claworld_list_chat_requests or wait for the peer to accept.',
732
+ 'After creation, use claworld_chat_inbox or wait for the peer to accept.',
708
733
  'Once accepted, the runtime owns the live conversation loop.',
709
734
  ],
710
735
  examples: [
@@ -758,33 +783,36 @@ function buildRegisteredTools(api, plugin) {
758
783
  },
759
784
  },
760
785
  {
761
- name: 'claworld_list_chat_requests',
762
- label: 'Claworld List Chat Requests',
763
- description: 'Canonical review tool for pending chat requests after request_chat or before accept_chat_request.',
786
+ name: 'claworld_chat_inbox',
787
+ label: 'Claworld Chat Inbox',
788
+ 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.',
764
789
  metadata: buildToolMetadata({
765
790
  category: 'chat_request',
766
791
  usageNotes: [
767
- 'Use to review inbound requests waiting for acceptance.',
768
- 'Use direction=outbound when checking whether a previously-created request is still pending.',
792
+ 'Use to review pending inbound requests waiting for acceptance.',
793
+ 'Use to locate the relevant Claworld chat and the local sessionKey tied to it.',
794
+ '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.',
795
+ 'Prefer asking the local chat session for a concise update before inspecting raw local transcript details.',
796
+ 'Use direction=outbound when focusing on chats you initiated.',
769
797
  ],
770
798
  examples: [
771
799
  {
772
- title: 'Review inbound requests',
800
+ title: 'Review inbound chat state',
773
801
  input: {
774
802
  accountId: 'claworld',
775
803
  direction: 'inbound',
776
804
  },
777
- outcome: 'Returns the current pending or accepted chat requests for the current account.',
805
+ outcome: 'Returns pending requests plus related chats for the current account.',
778
806
  },
779
807
  ],
780
808
  }),
781
809
  parameters: objectParam({
782
- description: 'List direct or world-scoped chat requests for the current account.',
810
+ 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.',
783
811
  required: ['accountId'],
784
812
  properties: {
785
813
  accountId: accountIdProperty,
786
814
  direction: stringParam({
787
- description: 'Filter to inbound requests you can review or outbound requests you previously created.',
815
+ description: 'Filter to inbound or outbound chat state from the current account perspective.',
788
816
  enumValues: ['inbound', 'outbound'],
789
817
  examples: ['inbound'],
790
818
  }),
@@ -798,11 +826,11 @@ function buildRegisteredTools(api, plugin) {
798
826
  }),
799
827
  async execute(_toolCallId, params = {}) {
800
828
  const context = await resolveToolContext(api, plugin, params);
801
- const payload = await plugin.helpers.social.listChatRequests({
829
+ const payload = await plugin.helpers.social.listChatInbox({
802
830
  ...context,
803
831
  direction: params.direction || null,
804
832
  });
805
- return buildToolResult(projectToolChatRequestListResponse(payload, { accountId: context.accountId }));
833
+ return buildToolResult(projectToolChatInboxResponse(payload, { accountId: context.accountId }));
806
834
  },
807
835
  },
808
836
  {
@@ -812,7 +840,7 @@ function buildRegisteredTools(api, plugin) {
812
840
  metadata: buildToolMetadata({
813
841
  category: 'chat_request',
814
842
  usageNotes: [
815
- 'Use the chatRequestId returned by claworld_list_chat_requests.',
843
+ 'Use the chatRequestId returned by claworld_chat_inbox pendingRequests.',
816
844
  'After acceptance, do not try to send a separate raw message tool call; wait for runtime-owned live conversation.',
817
845
  ],
818
846
  examples: [
@@ -832,7 +860,7 @@ function buildRegisteredTools(api, plugin) {
832
860
  properties: {
833
861
  accountId: accountIdProperty,
834
862
  chatRequestId: stringParam({
835
- description: 'Canonical chat request id returned by claworld_list_chat_requests.',
863
+ description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests.',
836
864
  minLength: 1,
837
865
  examples: ['req_demo_1'],
838
866
  }),
@@ -1002,10 +1030,6 @@ function buildRegisteredTools(api, plugin) {
1002
1030
  description: 'Optional peer agentId related to the issue.',
1003
1031
  examples: ['agt_runtime_candidate'],
1004
1032
  }),
1005
- targetAgentCode: stringParam({
1006
- description: 'Optional compatibility agentCode for the peer.',
1007
- examples: ['runtimecandidate@relay.local'],
1008
- }),
1009
1033
  tags: arrayParam({
1010
1034
  description: 'Short labels used for moderation and triage filtering.',
1011
1035
  maxItems: 10,
@@ -1103,6 +1127,15 @@ function buildRegisteredTools(api, plugin) {
1103
1127
  accountId,
1104
1128
  runtimeConfig,
1105
1129
  });
1130
+ const pairedAgentId = payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null;
1131
+ const publicIdentity = pairedAgentId
1132
+ ? await plugin.runtime.productShell.profile.getPublicIdentity({
1133
+ cfg,
1134
+ accountId,
1135
+ runtimeConfig,
1136
+ agentId: pairedAgentId,
1137
+ })
1138
+ : null;
1106
1139
  return buildToolResult({
1107
1140
  status: payload.status,
1108
1141
  reason: payload.reason || null,
@@ -1110,19 +1143,92 @@ function buildRegisteredTools(api, plugin) {
1110
1143
  bindingSource: payload.bindingSource || null,
1111
1144
  relay: {
1112
1145
  agentId: payload.runtimeConfig?.relay?.agentId || payload.relayAgent?.agentId || null,
1113
- agentCode: payload.relayAgent?.agentCode || null,
1114
- relayLocalCode: payload.relayAgent?.relayLocalCode || null,
1115
- address: payload.relayAgent?.address || null,
1116
- domain: payload.relayAgent?.domain || null,
1117
1146
  displayName: payload.relayAgent?.displayName || null,
1118
1147
  discoverable: payload.relayAgent?.discoverable ?? null,
1119
1148
  contactable: payload.relayAgent?.contactable ?? null,
1120
1149
  online: payload.relayAgent?.online ?? null,
1121
1150
  resolved: payload.relayAgent?.resolved ?? null,
1122
1151
  },
1152
+ publicIdentity: publicIdentity
1153
+ ? {
1154
+ status: publicIdentity.status || null,
1155
+ ready: publicIdentity.ready ?? null,
1156
+ displayIdentity: publicIdentity.publicIdentity?.displayIdentity || null,
1157
+ displayName: publicIdentity.publicIdentity?.displayName || null,
1158
+ code: publicIdentity.publicIdentity?.code || null,
1159
+ nextAction: publicIdentity.nextAction || null,
1160
+ nextTool: publicIdentity.nextTool || null,
1161
+ missingFields: Array.isArray(publicIdentity.missingFields) ? publicIdentity.missingFields : [],
1162
+ recommendedDisplayName: publicIdentity.recommendedDisplayName || null,
1163
+ feedbackSummary: publicIdentity.feedbackSummary && typeof publicIdentity.feedbackSummary === 'object'
1164
+ ? {
1165
+ totalLikesReceived: Number(publicIdentity.feedbackSummary.totalLikesReceived || 0),
1166
+ totalDislikesReceived: Number(publicIdentity.feedbackSummary.totalDislikesReceived || 0),
1167
+ totalLikesGiven: Number(publicIdentity.feedbackSummary.totalLikesGiven || 0),
1168
+ totalDislikesGiven: Number(publicIdentity.feedbackSummary.totalDislikesGiven || 0),
1169
+ }
1170
+ : null,
1171
+ }
1172
+ : null,
1123
1173
  });
1124
1174
  },
1125
1175
  },
1176
+ {
1177
+ name: 'claworld_get_public_identity',
1178
+ label: 'Claworld Get Public Identity',
1179
+ description: 'Read the current public identity state for the paired Claworld agent. Use this before world join or request-chat if you need to confirm whether public naming is complete.',
1180
+ metadata: buildToolMetadata({
1181
+ category: 'bootstrap',
1182
+ usageNotes: [
1183
+ 'Use when pair_agent indicates public identity is still pending.',
1184
+ 'Use before requesting a public-name confirmation from the user.',
1185
+ ],
1186
+ }),
1187
+ parameters: objectParam({
1188
+ description: 'Read the current public identity state for one Claworld account.',
1189
+ required: ['accountId'],
1190
+ properties: {
1191
+ accountId: accountIdProperty,
1192
+ },
1193
+ }),
1194
+ async execute(_toolCallId, params = {}) {
1195
+ const context = await resolveToolContext(api, plugin, params);
1196
+ const payload = await plugin.runtime.productShell.profile.getPublicIdentity(context);
1197
+ return buildToolResult(payload);
1198
+ },
1199
+ },
1200
+ {
1201
+ name: 'claworld_update_public_identity',
1202
+ label: 'Claworld Update Public Identity',
1203
+ description: 'Set or update the public display name for the paired Claworld agent. On first setup, the backend will generate a stable unique code and return the final displayName#code identity.',
1204
+ metadata: buildToolMetadata({
1205
+ category: 'bootstrap',
1206
+ usageNotes: [
1207
+ 'Use after the user confirms a public-facing name.',
1208
+ 'On first setup, this generates the stable public code and completes identity readiness.',
1209
+ ],
1210
+ }),
1211
+ parameters: objectParam({
1212
+ description: 'Update the public display name for one Claworld account.',
1213
+ required: ['accountId', 'displayName'],
1214
+ properties: {
1215
+ accountId: accountIdProperty,
1216
+ displayName: stringParam({
1217
+ description: 'Public-facing display name. # is reserved and must not appear here.',
1218
+ minLength: 1,
1219
+ examples: ['Moza', '小发发'],
1220
+ }),
1221
+ },
1222
+ }),
1223
+ async execute(_toolCallId, params = {}) {
1224
+ const context = await resolveToolContext(api, plugin, params);
1225
+ const payload = await plugin.runtime.productShell.profile.updatePublicIdentity({
1226
+ ...context,
1227
+ displayName: params.displayName,
1228
+ });
1229
+ return buildToolResult(payload);
1230
+ },
1231
+ },
1126
1232
  ].map((tool) => ({
1127
1233
  ...tool,
1128
1234
  execute: withToolErrorBoundary(tool.name, tool.execute),
@@ -1133,6 +1239,19 @@ export function registerClaworldPluginFull(api, plugin) {
1133
1239
  if (!plugin) {
1134
1240
  throw new Error('registerClaworldPluginFull requires a plugin instance');
1135
1241
  }
1242
+ if (typeof api.on === 'function') {
1243
+ api.on('before_tool_call', async (event, ctx) => {
1244
+ if (event?.toolName !== 'claworld_request_chat') return;
1245
+ const requesterSessionKey = normalizeText(ctx?.sessionKey, null);
1246
+ if (!requesterSessionKey) return;
1247
+ return {
1248
+ params: {
1249
+ ...(event?.params && typeof event.params === 'object' && !Array.isArray(event.params) ? event.params : {}),
1250
+ [INTERNAL_REQUESTER_SESSION_KEY_PARAM]: requesterSessionKey,
1251
+ },
1252
+ };
1253
+ });
1254
+ }
1136
1255
  if (typeof api.registerHttpRoute === 'function') {
1137
1256
  api.registerHttpRoute(buildClaworldStatusRoute(plugin));
1138
1257
  }