@xfxstudio/claworld 0.2.15 → 0.2.17

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.
@@ -1,3 +1,5 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
1
3
  import {
2
4
  applyRuntimeIdentity,
3
5
  buildRuntimeAuthHeaders,
@@ -74,6 +76,10 @@ function requireClientMessageId(value = null) {
74
76
  return normalized;
75
77
  }
76
78
 
79
+ function buildGeneratedClientMessageId() {
80
+ return `openclaw_manual_${randomUUID()}`;
81
+ }
82
+
77
83
  function buildRelayAgentSummary(item = {}) {
78
84
  const normalizedAgentId = normalizeClaworldText(item?.agentId, null);
79
85
  return {
@@ -338,9 +344,9 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
338
344
  }
339
345
  payload.source = normalizeClaworldText(payload.source, 'openclaw-claworld');
340
346
  payload.accountId = normalizeClaworldText(payload.accountId, runtimeConfig.accountId);
341
- const clientMessageId = requireClientMessageId(
347
+ const clientMessageId = normalizePluginOptionalText(
342
348
  outboundContext.clientMessageId || outboundContext.metadata?.clientMessageId || null
343
- );
349
+ ) || buildGeneratedClientMessageId();
344
350
 
345
351
  const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
346
352
  const result = await fetchJson(fetchImpl, `${baseUrl}/v1/messages`, {
@@ -436,22 +442,24 @@ function createRelayRouteError({
436
442
  async function createChatRequest({
437
443
  runtimeConfig,
438
444
  fromAgentId,
439
- targetAgentId,
445
+ displayName = null,
446
+ agentCode = null,
440
447
  openingMessage = null,
441
448
  worldId = null,
442
449
  requestContext = null,
443
450
  fetchImpl,
444
451
  }) {
445
- const normalizedTargetAgentId = normalizeClaworldText(targetAgentId, null);
446
- if (!normalizedTargetAgentId) {
452
+ const normalizedDisplayName = normalizeClaworldText(displayName, null);
453
+ const normalizedAgentCode = normalizeClaworldText(agentCode, null)?.toUpperCase() || null;
454
+ if (!normalizedDisplayName || !normalizedAgentCode) {
447
455
  throw createRuntimeBoundaryError({
448
456
  code: 'tool_input_invalid',
449
457
  category: 'input',
450
458
  status: 400,
451
- message: 'claworld chat request target requires targetAgentId',
452
- publicMessage: 'claworld chat request target requires targetAgentId',
459
+ message: 'claworld chat request target requires displayName and agentCode',
460
+ publicMessage: 'claworld chat request target requires displayName and agentCode',
453
461
  recoverable: true,
454
- context: { field: 'targetAgentId' },
462
+ context: { fields: ['displayName', 'agentCode'] },
455
463
  });
456
464
  }
457
465
  const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
@@ -464,7 +472,8 @@ async function createChatRequest({
464
472
  },
465
473
  body: JSON.stringify({
466
474
  fromAgentId,
467
- targetAgentId: normalizedTargetAgentId,
475
+ displayName: normalizedDisplayName,
476
+ agentCode: normalizedAgentCode,
468
477
  openingMessage: normalizeClaworldText(openingMessage, null),
469
478
  ...(normalizeClaworldText(worldId, null) ? { worldId: normalizeClaworldText(worldId, null) } : {}),
470
479
  ...(requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
@@ -478,7 +487,11 @@ async function createChatRequest({
478
487
  runtimeConfig,
479
488
  code: 'chat_request_create_failed',
480
489
  publicMessage: 'failed to create chat request',
481
- context: { fromAgentId, targetAgentId: normalizedTargetAgentId },
490
+ context: {
491
+ fromAgentId,
492
+ displayName: normalizedDisplayName,
493
+ agentCode: normalizedAgentCode,
494
+ },
482
495
  });
483
496
  }
484
497
  return result.body || {};
@@ -772,6 +785,7 @@ async function fetchPublicIdentity({
772
785
  totalLikesGiven: 0,
773
786
  totalDislikesGiven: 0,
774
787
  },
788
+ profile: null,
775
789
  };
776
790
  }
777
791
 
@@ -959,6 +973,53 @@ async function updateChatRequestApprovalPolicy({
959
973
  return result.body || {};
960
974
  }
961
975
 
976
+ async function updateGlobalProfile({
977
+ runtimeConfig,
978
+ agentId = null,
979
+ profile = '',
980
+ fetchImpl,
981
+ }) {
982
+ if (!resolveRuntimeAppToken(runtimeConfig)) {
983
+ throw createRuntimeBoundaryError({
984
+ code: 'claworld_account_unactivated',
985
+ category: 'conflict',
986
+ status: 409,
987
+ message: 'claworld account must be activated before updating profile',
988
+ publicMessage: 'activate the Claworld account before updating profile',
989
+ recoverable: true,
990
+ });
991
+ }
992
+
993
+ const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
994
+ const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile`, {
995
+ method: 'POST',
996
+ headers: {
997
+ 'content-type': 'application/json',
998
+ ...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
999
+ ...buildRuntimeAuthHeaders(runtimeConfig),
1000
+ },
1001
+ body: JSON.stringify({
1002
+ accountId: runtimeConfig.accountId || null,
1003
+ ...(agentId ? { agentId } : {}),
1004
+ action: 'update_profile',
1005
+ profile,
1006
+ }),
1007
+ });
1008
+ if (!result.ok) {
1009
+ createRelayRouteError({
1010
+ result,
1011
+ runtimeConfig,
1012
+ code: 'profile_update_failed',
1013
+ publicMessage: 'failed to update profile',
1014
+ context: {
1015
+ accountId: runtimeConfig.accountId || null,
1016
+ agentId: normalizeClaworldText(agentId, null),
1017
+ },
1018
+ });
1019
+ }
1020
+ return result.body || {};
1021
+ }
1022
+
962
1023
  async function renderAgentCard({
963
1024
  runtimeConfig,
964
1025
  agentId = null,
@@ -1013,78 +1074,6 @@ async function renderAgentCard({
1013
1074
  return result.body || {};
1014
1075
  }
1015
1076
 
1016
- async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
1017
- if (typeof fetchImpl !== 'function') {
1018
- throw new Error('fetch is unavailable for relay registration');
1019
- }
1020
-
1021
- const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
1022
- const registration = normalizeRuntimeRegistration(runtimeConfig);
1023
- const registerResult = await fetchJson(fetchImpl, `${baseUrl}/v1/agents/register`, {
1024
- method: 'POST',
1025
- headers: buildRuntimeAuthHeaders(runtimeConfig, {
1026
- accept: 'application/json',
1027
- 'content-type': 'application/json',
1028
- ...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
1029
- }),
1030
- body: JSON.stringify({
1031
- ...(registration.displayName ? { displayName: registration.displayName } : {}),
1032
- }),
1033
- });
1034
-
1035
- if (!registerResult.ok) {
1036
- logger.error?.('[claworld:bootstrap] register relay agent failed', {
1037
- accountId: runtimeConfig.accountId,
1038
- status: registerResult.status,
1039
- body: registerResult.body,
1040
- });
1041
-
1042
- const errorCode = normalizeClaworldText(registerResult.body?.error, 'relay_agent_registration_failed');
1043
- const category = registerResult.status === 401
1044
- ? 'auth'
1045
- : registerResult.status === 403
1046
- ? 'policy'
1047
- : registerResult.status === 409
1048
- ? 'conflict'
1049
- : registerResult.status >= 500
1050
- ? 'transport'
1051
- : 'config';
1052
- const publicMessage = 'relay registration failed';
1053
-
1054
- throw createRuntimeBoundaryError({
1055
- code: errorCode,
1056
- category,
1057
- status: registerResult.status,
1058
- message: `failed to register relay agent: ${registerResult.status}`,
1059
- publicMessage,
1060
- recoverable: registerResult.status >= 500,
1061
- context: {
1062
- accountId: runtimeConfig.accountId || null,
1063
- conflictingAgentId: normalizeClaworldText(registerResult.body?.agent?.agentId, null),
1064
- appTokenConfigured: Boolean(resolveRuntimeAppToken(runtimeConfig)),
1065
- },
1066
- });
1067
- }
1068
-
1069
- const registeredAgent = registerResult.body?.agent || null;
1070
- const appToken = normalizeClaworldText(registerResult.body?.appToken, resolveRuntimeAppToken(runtimeConfig));
1071
- if (!registeredAgent?.agentId || !appToken) {
1072
- throw new Error('relay registration did not produce relay agent binding');
1073
- }
1074
-
1075
- return {
1076
- bindingSource: normalizeClaworldText(
1077
- registerResult.body?.bindingSource,
1078
- resolveRuntimeAppToken(runtimeConfig) ? 'provided_app_token' : 'created_agent_app_token',
1079
- ),
1080
- runtimeConfig: applyRuntimeIdentity(runtimeConfig, {
1081
- agentId: registeredAgent.agentId,
1082
- appToken,
1083
- }),
1084
- relayAgent: buildRelayAgentSummary(registeredAgent, runtimeConfig),
1085
- };
1086
- }
1087
-
1088
1077
  async function fetchRelayAgents({ runtimeConfig, fetchImpl, logger }) {
1089
1078
  if (typeof fetchImpl !== 'function') {
1090
1079
  throw new Error('fetch is unavailable for relay agent lookup');
@@ -1148,40 +1137,6 @@ async function resolveRelayAgentSummary({
1148
1137
  };
1149
1138
  }
1150
1139
 
1151
- async function ensureAgentPairing({ runtimeConfig, fetchImpl, logger }) {
1152
- const binding = await ensureRelayBinding({ runtimeConfig, fetchImpl, logger });
1153
- const pairedRuntimeConfig = binding.runtimeConfig;
1154
- const relayAgentId = normalizeClaworldText(pairedRuntimeConfig.relay?.agentId, null);
1155
-
1156
- if (!relayAgentId) {
1157
- return {
1158
- status: 'unpaired',
1159
- reason: 'missing_app_token_or_registration',
1160
- bindingSource: binding.bindingSource,
1161
- runtimeConfig: pairedRuntimeConfig,
1162
- relayAgent: await resolveRelayAgentSummary({
1163
- runtimeConfig: pairedRuntimeConfig,
1164
- fetchImpl,
1165
- logger,
1166
- agentId: relayAgentId,
1167
- }),
1168
- };
1169
- }
1170
-
1171
- return {
1172
- status: 'paired',
1173
- reason: null,
1174
- bindingSource: binding.bindingSource,
1175
- runtimeConfig: pairedRuntimeConfig,
1176
- relayAgent: await resolveRelayAgentSummary({
1177
- runtimeConfig: pairedRuntimeConfig,
1178
- fetchImpl,
1179
- logger,
1180
- agentId: relayAgentId,
1181
- }),
1182
- };
1183
- }
1184
-
1185
1140
  async function fetchPostSetupWorldDirectory({ cfg, accountId, runtimeConfig, limit = null, sort = null, page = null, fetchImpl, logger }) {
1186
1141
  if (typeof fetchImpl !== 'function') {
1187
1142
  throw new Error('fetch is unavailable for claworld product-shell helper');
@@ -1227,24 +1182,32 @@ async function ensureRelayBinding({ runtimeConfig, fetchImpl, logger }) {
1227
1182
  };
1228
1183
  }
1229
1184
 
1230
- if (!appToken && !registration.enabled) {
1231
- return { runtimeConfig: normalizedRuntimeConfig, bindingSource: 'no_registration_context' };
1185
+ if (appToken) {
1186
+ const identityPayload = await fetchPublicIdentity({
1187
+ runtimeConfig: normalizedRuntimeConfig,
1188
+ agentId: null,
1189
+ generateShareCard: false,
1190
+ expiresInSeconds: null,
1191
+ fetchImpl,
1192
+ });
1193
+ const resolvedAgentId = normalizeClaworldText(identityPayload?.agentId, null);
1194
+ if (resolvedAgentId) {
1195
+ return {
1196
+ runtimeConfig: applyRuntimeIdentity(normalizedRuntimeConfig, { agentId: resolvedAgentId }),
1197
+ bindingSource: 'configured_app_token',
1198
+ };
1199
+ }
1200
+ logger.info?.('[claworld:bootstrap] configured credential is missing relay.agentId; waiting for a later authenticated account read or update');
1201
+ return {
1202
+ runtimeConfig: normalizedRuntimeConfig,
1203
+ bindingSource: 'configured_app_token',
1204
+ };
1232
1205
  }
1233
1206
 
1234
- logger.info?.('[claworld:bootstrap] ensureRelayBinding start', {
1235
- accountId: normalizedRuntimeConfig.accountId,
1236
- serverUrl: normalizedRuntimeConfig.serverUrl,
1237
- appTokenConfigured: Boolean(appToken),
1238
- registrationEnabled: registration.enabled,
1239
- displayName: registration.displayName || null,
1240
- hasRelayAgentId: Boolean(normalizedRuntimeConfig.relay?.agentId),
1241
- });
1242
-
1243
- return await registerRelayBinding({
1207
+ return {
1244
1208
  runtimeConfig: normalizedRuntimeConfig,
1245
- fetchImpl,
1246
- logger,
1247
- });
1209
+ bindingSource: registration.enabled ? 'registration_pending' : 'unbound',
1210
+ };
1248
1211
  }
1249
1212
 
1250
1213
  function resolveDeliveryWorldId(delivery = {}) {
@@ -2401,37 +2364,56 @@ async function updateRuntimePublicIdentity(context = {}) {
2401
2364
  : resolvedContext.runtimeConfig;
2402
2365
  const nextAgentId = normalizeClaworldText(
2403
2366
  runtimeActivation?.agentId,
2367
+ normalizeClaworldText(
2368
+ updateResult?.agentId,
2369
+ null,
2370
+ ),
2371
+ ) || normalizeClaworldText(
2404
2372
  normalizeClaworldText(resolvedContext.agentId, normalizeClaworldText(nextRuntimeConfig?.relay?.agentId, null)),
2373
+ null,
2405
2374
  );
2375
+ const boundRuntimeConfig = nextAgentId
2376
+ ? applyRuntimeIdentity(nextRuntimeConfig, { agentId: nextAgentId })
2377
+ : nextRuntimeConfig;
2406
2378
 
2407
- if (runtimeActivation && resolveRuntimeAppToken(nextRuntimeConfig)) {
2379
+ const previousAgentId = normalizeClaworldText(
2380
+ resolvedContext.runtimeConfig?.relay?.agentId,
2381
+ normalizeClaworldText(resolvedContext.agentId, null),
2382
+ );
2383
+ const shouldPersistRuntimeBinding = Boolean(
2384
+ resolveRuntimeAppToken(nextRuntimeConfig)
2385
+ && nextAgentId
2386
+ && (runtimeActivation || previousAgentId !== nextAgentId),
2387
+ );
2388
+
2389
+ if (shouldPersistRuntimeBinding) {
2408
2390
  const runtimeResolution = resolvePluginRuntimeCandidate(context.runtime || null);
2409
2391
  try {
2410
2392
  await persistRuntimeAppToken({
2411
2393
  runtime: runtimeResolution.runtime,
2412
- accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
2413
- appToken: resolveRuntimeAppToken(nextRuntimeConfig),
2394
+ accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
2395
+ appToken: resolveRuntimeAppToken(boundRuntimeConfig),
2414
2396
  relayAgentId: nextAgentId,
2415
2397
  });
2416
2398
  } catch (error) {
2417
2399
  logger.warn?.('[claworld:profile] failed to persist activated runtime binding', {
2418
- accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
2400
+ accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
2419
2401
  error: error?.message || String(error),
2420
2402
  });
2421
2403
  }
2422
2404
 
2423
2405
  rememberAccountBinding({
2424
- runtimeConfig: nextRuntimeConfig,
2425
- accountId: resolvedContext.accountId || nextRuntimeConfig.accountId || null,
2426
- bindingSource: 'activated_app_token',
2406
+ runtimeConfig: boundRuntimeConfig,
2407
+ accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
2408
+ bindingSource: runtimeActivation ? 'activated_app_token' : 'configured_app_token',
2427
2409
  });
2428
2410
 
2429
- const accountKey = resolveAccountBindingKey(nextRuntimeConfig, resolvedContext.accountId || null);
2411
+ const accountKey = resolveAccountBindingKey(boundRuntimeConfig, resolvedContext.accountId || null);
2430
2412
  const currentRuntimeContext = accountRuntimeContexts.get(accountKey) || null;
2431
2413
  if (currentRuntimeContext) {
2432
2414
  accountRuntimeContexts.set(accountKey, {
2433
2415
  ...currentRuntimeContext,
2434
- runtimeConfig: nextRuntimeConfig,
2416
+ runtimeConfig: boundRuntimeConfig,
2435
2417
  deferredFailure: null,
2436
2418
  deferredErrorMessage: null,
2437
2419
  });
@@ -2455,16 +2437,28 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2455
2437
  });
2456
2438
  }
2457
2439
 
2458
- async function generateRuntimeProfileCard(context = {}) {
2459
- const resolvedContext = await resolveBoundRuntimeContext(context);
2460
- return renderAgentCard({
2461
- runtimeConfig: resolvedContext.runtimeConfig,
2462
- agentId: context.agentId || resolvedContext.agentId || null,
2463
- expiresInSeconds: context.expiresInSeconds ?? null,
2464
- forceRegenerate: context.forceRegenerate !== false,
2465
- fetchImpl,
2466
- });
2467
- }
2440
+ async function updateRuntimeProfile(context = {}) {
2441
+ const resolvedContext = await resolveBoundRuntimeContext(context);
2442
+ return updateGlobalProfile({
2443
+ runtimeConfig: resolvedContext.runtimeConfig,
2444
+ agentId: resolvedContext.agentId || null,
2445
+ profile: Object.prototype.hasOwnProperty.call(context, 'profile')
2446
+ ? (context.profile == null ? '' : String(context.profile))
2447
+ : '',
2448
+ fetchImpl,
2449
+ });
2450
+ }
2451
+
2452
+ async function generateRuntimeProfileCard(context = {}) {
2453
+ const resolvedContext = await resolveBoundRuntimeContext(context);
2454
+ return renderAgentCard({
2455
+ runtimeConfig: resolvedContext.runtimeConfig,
2456
+ agentId: context.agentId || resolvedContext.agentId || null,
2457
+ expiresInSeconds: context.expiresInSeconds ?? null,
2458
+ forceRegenerate: context.forceRegenerate !== false,
2459
+ fetchImpl,
2460
+ });
2461
+ }
2468
2462
 
2469
2463
  return {
2470
2464
  id: 'claworld',
@@ -2493,7 +2487,7 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2493
2487
  messageToolHints: () => [
2494
2488
  '- Claworld message targets are canonical `agentId` values such as `agt_xxx`.',
2495
2489
  '- Omit `target` to keep replying inside the current A2A session when the runtime already inferred the peer.',
2496
- '- Resolve public identity like `displayName#code` to `agentId` before opening a new relay session to another agent.',
2490
+ '- For new chat requests, use the target `displayName` plus public `agentCode`; the backend resolves by `agentCode` and returns a warning if the displayName is stale.',
2497
2491
  ],
2498
2492
  },
2499
2493
  reload: { configPrefixes: ['channels.claworld'] },
@@ -2609,11 +2603,6 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2609
2603
  helpers: {
2610
2604
  resolveToolRuntimeContext: resolveBoundRuntimeContext,
2611
2605
  pairing: {
2612
- ensureAgentPairing: async (context = {}) => ensureAgentPairing({
2613
- runtimeConfig: context.runtimeConfig || resolveClaworldRuntimeConfig(context.cfg || {}, context.accountId || null),
2614
- fetchImpl,
2615
- logger,
2616
- }),
2617
2606
  resolveAgentIdentity: async (context = {}) => resolveRelayAgentSummary({
2618
2607
  runtimeConfig: context.runtimeConfig || resolveClaworldRuntimeConfig(context.cfg || {}, context.accountId || null),
2619
2608
  fetchImpl,
@@ -2634,7 +2623,8 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2634
2623
  return createChatRequest({
2635
2624
  runtimeConfig: resolvedContext.runtimeConfig,
2636
2625
  fromAgentId: resolvedContext.agentId || null,
2637
- targetAgentId: context.targetAgentId || null,
2626
+ displayName: context.displayName || null,
2627
+ agentCode: context.agentCode || null,
2638
2628
  openingMessage: context.openingMessage || context.message || context.text || null,
2639
2629
  worldId: context.worldId || null,
2640
2630
  requestContext,
@@ -2672,6 +2662,7 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2672
2662
  profile: {
2673
2663
  getPublicIdentity: getRuntimePublicIdentity,
2674
2664
  updatePublicIdentity: updateRuntimePublicIdentity,
2665
+ updateProfile: updateRuntimeProfile,
2675
2666
  updateChatRequestApprovalPolicy: updateRuntimeChatRequestApprovalPolicy,
2676
2667
  generateShareCard: generateRuntimeProfileCard,
2677
2668
  },
@@ -2800,6 +2791,7 @@ async function updateRuntimeChatRequestApprovalPolicy(context = {}) {
2800
2791
  profile: {
2801
2792
  getPublicIdentity: getRuntimePublicIdentity,
2802
2793
  updatePublicIdentity: updateRuntimePublicIdentity,
2794
+ updateProfile: updateRuntimeProfile,
2803
2795
  updateChatRequestApprovalPolicy: updateRuntimeChatRequestApprovalPolicy,
2804
2796
  generateShareCard: generateRuntimeProfileCard,
2805
2797
  },