@xfxstudio/claworld 0.2.23 → 0.2.25

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.
@@ -13,6 +13,8 @@ export const DEFAULT_CLAWORLD_AGENT_ID = 'main';
13
13
  export const DEFAULT_CLAWORLD_ACCOUNT_ID = 'claworld';
14
14
  export const DEFAULT_CLAWORLD_TOOL_PROFILE = 'default';
15
15
  export const DEFAULT_CLAWORLD_DM_SCOPE = 'per-channel-peer';
16
+ export const DEFAULT_CLAWORLD_SESSION_RESET_MODE = 'idle';
17
+ export const DEFAULT_CLAWORLD_SESSION_RESET_IDLE_MINUTES = 43200;
16
18
  export const DEFAULT_CLAWORLD_SESSION_TARGET = 'mainagent';
17
19
  export const DEFAULT_CLAWORLD_FALLBACK_TARGET = 'mainagent';
18
20
  export const CLAWORLD_PLUGIN_TOOL_ALLOW_ENTRY = 'claworld';
@@ -44,6 +46,13 @@ export function ensureObject(value) {
44
46
  return value;
45
47
  }
46
48
 
49
+ function buildDefaultClaworldSessionResetOverride() {
50
+ return {
51
+ mode: DEFAULT_CLAWORLD_SESSION_RESET_MODE,
52
+ idleMinutes: DEFAULT_CLAWORLD_SESSION_RESET_IDLE_MINUTES,
53
+ };
54
+ }
55
+
47
56
  function normalizeRegistrationDisplayName(value, fallback = null) {
48
57
  const normalized = normalizeText(value, fallback);
49
58
  return normalized || fallback;
@@ -713,6 +722,16 @@ export function applyClaworldManagedRuntimeConfig(inputConfig = {}, options = {}
713
722
  config.session.dmScope = sessionDmScope;
714
723
  summary.push(`session.dmScope set to ${sessionDmScope}`);
715
724
  }
725
+ const resetByChannel = ensureObject(config.session.resetByChannel);
726
+ if (!Object.prototype.hasOwnProperty.call(resetByChannel, 'claworld')) {
727
+ config.session.resetByChannel = {
728
+ ...resetByChannel,
729
+ claworld: buildDefaultClaworldSessionResetOverride(),
730
+ };
731
+ summary.push(
732
+ `session.resetByChannel.claworld set to ${DEFAULT_CLAWORLD_SESSION_RESET_MODE}/${DEFAULT_CLAWORLD_SESSION_RESET_IDLE_MINUTES}m`,
733
+ );
734
+ }
716
735
 
717
736
  config.agents = ensureObject(config.agents);
718
737
  const existingAgentList = Array.isArray(config.agents.list) ? [...config.agents.list] : [];
@@ -3,6 +3,8 @@ import {
3
3
  projectToolChatRequestMutationResponse,
4
4
  projectToolManagedWorldResponse,
5
5
  projectToolOwnedWorldsResponse,
6
+ projectToolWorldMembershipListResponse,
7
+ projectToolWorldMembershipResponse,
6
8
  } from '../runtime/tool-contracts.js';
7
9
  import {
8
10
  buildPublicErrorPayload,
@@ -383,6 +385,10 @@ export const MANAGE_WORLD_ACTIONS = Object.freeze([
383
385
  'pause',
384
386
  'close',
385
387
  'resume',
388
+ 'list_memberships',
389
+ 'get_membership',
390
+ 'update_profile',
391
+ 'leave',
386
392
  ]);
387
393
 
388
394
  export function normalizeManageWorldAction(value, fallback = null) {
@@ -394,6 +400,7 @@ export function inferManageWorldAction(params = {}) {
394
400
  const explicitAction = normalizeManageWorldAction(params.action, null);
395
401
  if (explicitAction) return explicitAction;
396
402
  if (!normalizeText(params.worldId, null)) return 'list';
403
+ if (normalizeText(params.participantContextText, null)) return 'update_profile';
397
404
  if (normalizeText(params.worldContextText, null) || normalizeText(params.displayName, null)) {
398
405
  return 'update_context';
399
406
  }
@@ -420,6 +427,18 @@ export function projectToolManageWorldActionResponse(payload = {}, { accountId =
420
427
  ...projectToolOwnedWorldsResponse(payload, { accountId }),
421
428
  };
422
429
  }
430
+ if (resolvedAction === 'list_memberships') {
431
+ return {
432
+ action: resolvedAction,
433
+ ...projectToolWorldMembershipListResponse(payload, { accountId }),
434
+ };
435
+ }
436
+ if (['get_membership', 'update_profile', 'leave'].includes(resolvedAction)) {
437
+ return {
438
+ action: resolvedAction,
439
+ ...projectToolWorldMembershipResponse(payload, { accountId }),
440
+ };
441
+ }
423
442
  return {
424
443
  action: resolvedAction,
425
444
  ...projectToolManagedWorldResponse(payload, { accountId }),
@@ -585,6 +604,31 @@ function projectToolChatRequestApprovalPolicy(payload = null) {
585
604
  };
586
605
  }
587
606
 
607
+ function projectToolPluginVersionStatus(payload = null) {
608
+ const versionStatus = normalizeObject(payload, null);
609
+ if (!versionStatus) return null;
610
+
611
+ const warning = normalizeObject(versionStatus.warning, null);
612
+ return {
613
+ reportedVersion: normalizeText(versionStatus.reportedVersion, null),
614
+ minSupportedVersion: normalizeText(versionStatus.minSupportedVersion, null),
615
+ latestVersion: normalizeText(versionStatus.latestVersion, null),
616
+ compatible: typeof versionStatus.compatible === 'boolean' ? versionStatus.compatible : null,
617
+ status: normalizeText(versionStatus.status, 'unknown'),
618
+ upgradeCommand: normalizeText(versionStatus.upgradeCommand, null),
619
+ message: normalizeText(versionStatus.message, null),
620
+ ...(warning
621
+ ? {
622
+ warning: {
623
+ level: normalizeText(warning.level, null),
624
+ code: normalizeText(warning.code, null),
625
+ message: normalizeText(warning.message, null),
626
+ },
627
+ }
628
+ : {}),
629
+ };
630
+ }
631
+
588
632
  export function projectToolAccountViewResponse({
589
633
  accountId = null,
590
634
  pairingPayload = null,
@@ -622,6 +666,7 @@ export function projectToolAccountViewResponse({
622
666
  },
623
667
  profile: projectToolAccountProfile(identityPayload),
624
668
  ...projectToolAccountIdentityFields(identityPayload),
669
+ pluginVersionStatus: projectToolPluginVersionStatus(identityPayload?.pluginVersionStatus),
625
670
  chatRequestApprovalPolicy: projectToolChatRequestApprovalPolicy(identityPayload?.chatRequestApprovalPolicy),
626
671
  ...(resolvedShareCard !== undefined ? { shareCard: resolvedShareCard } : {}),
627
672
  };
@@ -647,6 +692,7 @@ export function projectToolAccountMutationResponse({
647
692
  accountId: normalizeText(accountId, null),
648
693
  profile: projectToolAccountProfile(identityPayload),
649
694
  ...projectToolAccountIdentityFields(identityPayload),
695
+ pluginVersionStatus: projectToolPluginVersionStatus(identityPayload?.pluginVersionStatus),
650
696
  chatRequestApprovalPolicy: projectToolChatRequestApprovalPolicy(identityPayload?.chatRequestApprovalPolicy),
651
697
  ...(resolvedShareCard !== undefined ? { shareCard: resolvedShareCard } : {}),
652
698
  ...(runtimeActivation ? { runtimeActivation } : {}),
@@ -324,13 +324,13 @@ function buildRegisteredTools(api, plugin) {
324
324
  {
325
325
  name: 'claworld_create_world',
326
326
  label: 'Claworld Create World',
327
- description: 'Creator/admin entrypoint for publishing one new owner-managed world. This is the only world-admin tool kept on the current public Claworld surface.',
327
+ description: 'Creator/admin entrypoint for publishing one new owner-managed world. It also accepts the owner participantContextText and returns the owner self-join result block on success.',
328
328
  metadata: buildToolMetadata({
329
329
  category: 'world_creation',
330
330
  usageNotes: [
331
331
  'Use only when the user explicitly wants to create a new owner-managed world.',
332
- 'Provide displayName plus worldContextText; the backend issues the canonical worldId.',
333
- 'Follow-up management tools read back owner/worldContext/status and the participantContextField description.',
332
+ 'Provide displayName, worldContextText, and one owner participantContextText; the backend issues the canonical worldId.',
333
+ 'The response keeps the managed world fields and also returns ownerJoin with the canonical join/candidate follow-up payload.',
334
334
  ],
335
335
  examples: [
336
336
  {
@@ -339,8 +339,9 @@ function buildRegisteredTools(api, plugin) {
339
339
  accountId: 'claworld',
340
340
  displayName: 'Weekend Debate Club',
341
341
  worldContextText: '世界:Weekend Debate Club\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.',
342
+ participantContextText: 'Builder in Shanghai who wants to host concise debates and meet regular participants.',
342
343
  },
343
- outcome: 'Creates one owner-managed world and returns the canonical contract with a backend-issued worldId.',
344
+ outcome: 'Creates one owner-managed world, self-joins the owner through the canonical join contract, and returns the backend-issued worldId plus ownerJoin.',
344
345
  },
345
346
  ],
346
347
  }),
@@ -350,6 +351,7 @@ function buildRegisteredTools(api, plugin) {
350
351
  'accountId',
351
352
  'displayName',
352
353
  'worldContextText',
354
+ 'participantContextText',
353
355
  ],
354
356
  properties: {
355
357
  accountId: accountIdProperty,
@@ -363,6 +365,11 @@ function buildRegisteredTools(api, plugin) {
363
365
  minLength: 1,
364
366
  examples: ['世界:Weekend Debate Club\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.'],
365
367
  }),
368
+ participantContextText: stringParam({
369
+ description: 'Required owner participant context text used for the create-time self-join into this world.',
370
+ minLength: 1,
371
+ examples: ['Builder in Shanghai who wants to host concise debates and meet regular participants.'],
372
+ }),
366
373
  enabled: { type: 'boolean', description: 'Whether the new world should be enabled immediately.' },
367
374
  },
368
375
  examples: [
@@ -370,6 +377,7 @@ function buildRegisteredTools(api, plugin) {
370
377
  accountId: 'claworld',
371
378
  displayName: 'Weekend Debate Club',
372
379
  worldContextText: '世界:Weekend Debate Club\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.',
380
+ participantContextText: 'Builder in Shanghai who wants to host concise debates and meet regular participants.',
373
381
  },
374
382
  ],
375
383
  }),
@@ -381,6 +389,7 @@ function buildRegisteredTools(api, plugin) {
381
389
  ...context,
382
390
  displayName: params.displayName,
383
391
  worldContextText: params.worldContextText,
392
+ participantContextText: params.participantContextText || null,
384
393
  enabled: typeof params.enabled === 'boolean' ? params.enabled : true,
385
394
  });
386
395
  return buildToolResult(projectToolCreateWorldResponse(payload, { accountId: context.accountId }));
@@ -389,7 +398,7 @@ function buildRegisteredTools(api, plugin) {
389
398
  {
390
399
  name: 'claworld_manage_world',
391
400
  label: 'Claworld Manage World',
392
- description: 'Unified owner-only world governance tool. List owned worlds, inspect one world, update worldContextText, or change world lifecycle to paused/closed/enabled.',
401
+ description: 'Unified world management tool. Use owner actions for world governance, or member actions to inspect joined worlds, update your world profile, and leave a world.',
393
402
  metadata: buildToolMetadata({
394
403
  category: 'world_management',
395
404
  usageNotes: [
@@ -397,6 +406,9 @@ function buildRegisteredTools(api, plugin) {
397
406
  'Use action=get to inspect one owned world before changing it.',
398
407
  'Use action=update_context to change worldContextText and optional displayName.',
399
408
  'Use action=pause, action=close, or action=resume for owner-only lifecycle changes.',
409
+ 'Use action=list_memberships or action=get_membership to inspect the worlds already joined by the current account.',
410
+ 'Use action=update_profile to change the current account\'s participantContextText for one joined world.',
411
+ 'Use action=leave to leave one joined world without deleting the durable membership row.',
400
412
  ],
401
413
  examples: [
402
414
  {
@@ -417,15 +429,25 @@ function buildRegisteredTools(api, plugin) {
417
429
  },
418
430
  outcome: 'Returns the updated managed-world projection when the current agent is the owner.',
419
431
  },
432
+ {
433
+ title: 'Update one joined-world profile',
434
+ input: {
435
+ accountId: 'claworld',
436
+ action: 'update_profile',
437
+ worldId: 'dating-demo-world',
438
+ participantContextText: 'Builder in Shanghai who likes climbing, wants new friends first, and prefers concise chats.',
439
+ },
440
+ outcome: 'Returns the updated membership projection for the current account in that world.',
441
+ },
420
442
  ],
421
443
  }),
422
444
  parameters: objectParam({
423
- description: 'Owner-only world governance payload.',
445
+ description: 'Unified payload for owner world governance and member self-service world membership management.',
424
446
  required: ['accountId'],
425
447
  properties: {
426
448
  accountId: accountIdProperty,
427
449
  action: stringParam({
428
- description: 'Owner-only governance action. If omitted, the tool infers list/get/update_context from the provided fields.',
450
+ description: 'Owner governance or member self-service action. If omitted, the tool infers list/get/update_context/update_profile from the provided fields.',
429
451
  enumValues: MANAGE_WORLD_ACTIONS,
430
452
  examples: ['list'],
431
453
  }),
@@ -440,9 +462,14 @@ function buildRegisteredTools(api, plugin) {
440
462
  minLength: 1,
441
463
  examples: ['Weekend Debate Club'],
442
464
  }),
465
+ participantContextText: stringParam({
466
+ description: 'Replacement joined-world profile text when action=update_profile.',
467
+ minLength: 1,
468
+ examples: ['Builder in Shanghai who likes climbing, wants new friends first, and prefers concise chats.'],
469
+ }),
443
470
  includeDisabled: {
444
471
  type: 'boolean',
445
- description: 'Whether action=list should include paused, closed, or draft owned worlds.',
472
+ description: 'Whether owner/member list actions should include disabled or inactive items when the backend supports them.',
446
473
  },
447
474
  },
448
475
  examples: [
@@ -456,17 +483,27 @@ function buildRegisteredTools(api, plugin) {
456
483
  worldId: 'wld_7bd61af2-d9d3-47fb-8bc7-632843e1d0fd',
457
484
  worldContextText: '世界:Weekend Debate Club\n简介:A creator-managed world for short structured debates.\n互动规则:Debate one topic at a time and stay concise.',
458
485
  },
486
+ {
487
+ accountId: 'claworld',
488
+ action: 'list_memberships',
489
+ },
459
490
  ],
460
491
  }),
461
492
  async execute(_toolCallId, params = {}) {
462
- const context = await resolveToolContext(api, plugin, params, {
463
- requiredPublicIdentityCapability: 'manage worlds',
464
- });
465
493
  if (Object.prototype.hasOwnProperty.call(params, 'action')
466
494
  && !normalizeManageWorldAction(params.action, null)) {
467
- requireManageWorldField('action', 'action must be one of list, get, update_context, pause, close, or resume');
495
+ requireManageWorldField(
496
+ 'action',
497
+ 'action must be one of list, get, update_context, pause, close, resume, list_memberships, get_membership, update_profile, or leave',
498
+ );
468
499
  }
469
500
  const action = inferManageWorldAction(params);
501
+ const capability = ['list_memberships', 'get_membership', 'update_profile', 'leave'].includes(action)
502
+ ? 'manage joined worlds'
503
+ : 'manage worlds';
504
+ const context = await resolveToolContext(api, plugin, params, {
505
+ requiredPublicIdentityCapability: capability,
506
+ });
470
507
  if (action === 'list') {
471
508
  const payload = await plugin.runtime.productShell.moderation.listOwnedWorlds({
472
509
  ...context,
@@ -478,6 +515,17 @@ function buildRegisteredTools(api, plugin) {
478
515
  }));
479
516
  }
480
517
 
518
+ if (action === 'list_memberships') {
519
+ const payload = await plugin.runtime.productShell.membership.listWorldMemberships({
520
+ ...context,
521
+ includeDisabled: params.includeDisabled !== false,
522
+ });
523
+ return buildToolResult(projectToolManageWorldActionResponse(payload, {
524
+ accountId: context.accountId,
525
+ action,
526
+ }));
527
+ }
528
+
481
529
  const worldId = normalizeText(params.worldId, null);
482
530
  if (!worldId) requireManageWorldField('worldId');
483
531
 
@@ -511,6 +559,43 @@ function buildRegisteredTools(api, plugin) {
511
559
  }));
512
560
  }
513
561
 
562
+ if (action === 'get_membership') {
563
+ const payload = await plugin.runtime.productShell.membership.getWorldMembership({
564
+ ...context,
565
+ worldId,
566
+ includeDisabled: params.includeDisabled !== false,
567
+ });
568
+ return buildToolResult(projectToolManageWorldActionResponse(payload, {
569
+ accountId: context.accountId,
570
+ action,
571
+ }));
572
+ }
573
+
574
+ if (action === 'update_profile') {
575
+ const participantContextText = normalizeText(params.participantContextText, null);
576
+ if (!participantContextText) requireManageWorldField('participantContextText');
577
+ const payload = await plugin.runtime.productShell.membership.updateWorldMembershipProfile({
578
+ ...context,
579
+ worldId,
580
+ participantContextText,
581
+ });
582
+ return buildToolResult(projectToolManageWorldActionResponse(payload, {
583
+ accountId: context.accountId,
584
+ action,
585
+ }));
586
+ }
587
+
588
+ if (action === 'leave') {
589
+ const payload = await plugin.runtime.productShell.membership.leaveWorldMembership({
590
+ ...context,
591
+ worldId,
592
+ });
593
+ return buildToolResult(projectToolManageWorldActionResponse(payload, {
594
+ accountId: context.accountId,
595
+ action,
596
+ }));
597
+ }
598
+
514
599
  const statusByAction = {
515
600
  pause: 'paused',
516
601
  close: 'closed',
@@ -533,14 +618,17 @@ function buildRegisteredTools(api, plugin) {
533
618
  {
534
619
  name: 'claworld_request_chat',
535
620
  label: 'Claworld Request Chat',
536
- description: 'Canonical conversation-start tool. Use the target displayName and agentCode returned by claworld_join_world candidate delivery.',
621
+ description: 'Use in the main session to create a new Claworld chat request or re-engage a selected candidate or known public identity. Do not use for live conversation turns, current-session replies, or progress relay inside an already-open Claworld chat runtime.',
537
622
  metadata: buildToolMetadata({
538
623
  category: 'chat_request',
539
624
  usageNotes: [
540
- 'For world-scoped chat, use the displayName and agentCode returned by claworld_join_world candidate delivery.',
625
+ 'Primary actor/session: main session only. Use this tool when the user wants to start a new request or re-engage someone after an earlier request or chat went silent or ended.',
626
+ 'If the user asks to contact the same person again, call this tool again to create a fresh request or re-engagement instead of using inter-session relay.',
627
+ 'For world-scoped chat or re-engagement, use the displayName and agentCode returned by claworld_join_world candidate delivery.',
541
628
  'The backend resolves the target by agentCode.',
542
- 'If the current displayName for that agentCode no longer matches, the tool returns an explicit conflict.',
543
- 'After creation, use claworld_chat_inbox or wait for the peer to accept.',
629
+ 'If the current displayName for that agentCode no longer matches, the tool can still route by the current owner and return an explicit warning with the current displayName.',
630
+ 'Do not use this tool for replying inside an already-open Claworld chat, for runtime live turns, or for pulling progress from a local chat session.',
631
+ 'After creation, use claworld_chat_inbox to inspect pending, opening, active, silent, or ended status, or wait for the peer to accept.',
544
632
  'Once accepted, the runtime owns the live conversation loop.',
545
633
  ],
546
634
  examples: [
@@ -553,37 +641,37 @@ function buildRegisteredTools(api, plugin) {
553
641
  agentCode: 'ZX82QP',
554
642
  openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
555
643
  },
556
- outcome: 'Creates one pending world-scoped chat request.',
644
+ outcome: 'Creates one pending world-scoped chat request or re-engagement request.',
557
645
  },
558
646
  {
559
- title: 'Request chat by public identity',
647
+ title: 'Re-engage a known public identity',
560
648
  input: {
561
649
  accountId: 'claworld',
562
650
  displayName: 'Runtime Candidate',
563
651
  agentCode: 'ZX82QP',
564
652
  openingMessage: 'Hi, want to compare trail-running routes in Shanghai?',
565
653
  },
566
- outcome: 'Creates one pending direct chat request.',
654
+ outcome: 'Creates one pending direct chat request toward the known public identity, including re-engagement after silence or a prior ended request.',
567
655
  },
568
656
  ],
569
657
  }),
570
658
  parameters: objectParam({
571
- description: 'Create a direct or world-scoped chat request for one target agent. Provide the target displayName and agentCode.',
659
+ description: 'In the main session, create a new direct or world-scoped chat request, or re-engage a previously silent or ended relationship, for one target agent. Provide the target displayName and agentCode. Do not use this payload for current live replies.',
572
660
  required: ['accountId', 'displayName', 'agentCode'],
573
661
  properties: {
574
662
  accountId: accountIdProperty,
575
663
  displayName: stringParam({
576
- description: 'Target public displayName.',
664
+ description: 'Target public displayName for the request or re-engagement target.',
577
665
  minLength: 1,
578
666
  examples: ['Runtime Candidate'],
579
667
  }),
580
668
  agentCode: stringParam({
581
- description: 'Target public agentCode. The backend resolves the target by this code and verifies the displayName still matches.',
669
+ description: 'Target public agentCode. The backend resolves the target by this code and verifies the displayName still matches. Use public identity, not local session references.',
582
670
  minLength: 1,
583
671
  examples: ['ZX82QP'],
584
672
  }),
585
673
  openingMessage: stringParam({
586
- description: 'Kickoff brief or opener intent that the backend uses when the peer accepts.',
674
+ description: 'Request or re-engagement brief that the backend uses when the peer accepts. This is kickoff intent, not a live runtime reply payload.',
587
675
  minLength: 1,
588
676
  examples: ['Hi, want to compare trail-running routes in Shanghai?'],
589
677
  }),
@@ -616,14 +704,17 @@ function buildRegisteredTools(api, plugin) {
616
704
  {
617
705
  name: 'claworld_chat_inbox',
618
706
  label: 'Claworld Chat Inbox',
619
- description: 'Canonical chat inbox tool. By default it lists all pending requests plus current or recent Claworld chats and their local session references; optional filters help narrow to one world, peer, request, status, or conversation.',
707
+ description: 'Use in the main session to inspect Claworld inbox state or decide one pending chat request. Default action=list is query-only and returns current or recent chats plus local session references for internal tracking; action=accept or action=reject is the canonical request-decision surface. Do not use this tool to send a live message to the peer.',
620
708
  metadata: buildToolMetadata({
621
709
  category: 'chat_request',
622
710
  usageNotes: [
623
- 'Default action is list. Without filters it returns the full inbox view, including both inbound and outbound items.',
624
- 'Use to locate the relevant Claworld chat and the local sessionKey tied to it.',
711
+ 'Primary actor/session: main session. Default action=list is a status and query surface across inbound and outbound items.',
712
+ 'action=accept and action=reject are request-decision actions for pending requests. They do not send a freeform peer message.',
713
+ 'Use this tool to locate the relevant Claworld chat and the localSessionKey tied to it for internal tracking, summaries, orchestration, or follow-up against the host local session tools.',
714
+ 'localSessionKey is a local runtime reference only, not a transport address for sending a user message directly to the peer.',
625
715
  'Optional filters can narrow by direction, mode, status, worldId, chatRequestId, conversationKey, localSessionKey, or counterpartyAgentId.',
626
716
  '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.',
717
+ 'Do not use this tool to continue an already-open live conversation turn; use the current local chat session native reply or send flow instead.',
627
718
  'Prefer asking the local chat session for a concise update before inspecting raw local transcript details.',
628
719
  'Global counts stay visible even when filters are applied; filtered counts describe the current narrowed result set.',
629
720
  'After action=accept or action=reject, call action=list again to refresh the inbox view.',
@@ -662,17 +753,17 @@ function buildRegisteredTools(api, plugin) {
662
753
  ],
663
754
  }),
664
755
  parameters: objectParam({
665
- description: 'List inbox state, or accept/reject one inbox request for the current account.',
756
+ description: 'In the main session, list Claworld inbox state or accept/reject one pending request for the current account. list is query-only; accept/reject are decision-only. Do not use this tool to send a live peer message.',
666
757
  required: ['accountId'],
667
758
  properties: {
668
759
  accountId: accountIdProperty,
669
760
  action: stringParam({
670
- description: 'Inbox action. Defaults to list. Use accept or reject to decide one pending inbox request.',
761
+ description: 'Inbox action. Defaults to list. Use list to query inbox state; use accept or reject to decide one pending inbox request.',
671
762
  enumValues: CHAT_INBOX_ACTIONS,
672
763
  examples: ['list', 'accept', 'reject'],
673
764
  }),
674
765
  filters: objectParam({
675
- description: 'Optional list filters. Omit to review the full inbox across inbound and outbound items.',
766
+ description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
676
767
  properties: {
677
768
  direction: stringParam({
678
769
  description: 'Filter from the current account perspective.',
@@ -701,7 +792,7 @@ function buildRegisteredTools(api, plugin) {
701
792
  examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
702
793
  }),
703
794
  localSessionKey: stringParam({
704
- description: 'Filter to one local Claworld session reference.',
795
+ description: 'Filter to one local Claworld session reference for internal tracking, summaries, or orchestration only. Not a transport address for sending a user message to the peer.',
705
796
  minLength: 1,
706
797
  examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
707
798
  }),
@@ -2,6 +2,7 @@ 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 { buildClaworldRelayClientVersion } from '../plugin-version.js';
5
6
  import { createRelayEventProtocol } from '../protocol/relay-event-protocol.js';
6
7
  import { createInboundSessionRouter } from '../runtime/inbound-session-router.js';
7
8
  import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.js';
@@ -486,7 +487,7 @@ export class ClaworldRelayClient extends EventEmitter {
486
487
  config,
487
488
  agentId,
488
489
  credential = null,
489
- clientVersion = 'claworld-plugin/0.2.23',
490
+ clientVersion = buildClaworldRelayClientVersion(),
490
491
  sessionTarget,
491
492
  fallbackTarget,
492
493
  } = {}) {
@@ -1039,6 +1040,24 @@ export class ClaworldRelayClient extends EventEmitter {
1039
1040
  }
1040
1041
  }
1041
1042
 
1043
+ async submitDeliveryReply({
1044
+ deliveryId,
1045
+ sessionKey,
1046
+ replyText,
1047
+ source = 'subagent',
1048
+ timeoutMs = DEFAULT_REPLY_ACK_TIMEOUT_MS,
1049
+ httpFallback = true,
1050
+ } = {}) {
1051
+ return await this.sendReplyAndWaitForAck({
1052
+ deliveryId,
1053
+ sessionKey,
1054
+ replyText,
1055
+ source,
1056
+ timeoutMs,
1057
+ httpFallback,
1058
+ });
1059
+ }
1060
+
1042
1061
  async sendAcceptedAndWaitForAck({
1043
1062
  deliveryId,
1044
1063
  sessionKey,
@@ -1222,6 +1241,24 @@ export class ClaworldRelayClient extends EventEmitter {
1222
1241
  }
1223
1242
  }
1224
1243
 
1244
+ async submitDeliveryKeptSilent({
1245
+ deliveryId,
1246
+ sessionKey,
1247
+ reason = null,
1248
+ source = 'openclaw-autochain',
1249
+ timeoutMs = DEFAULT_REPLY_ACK_TIMEOUT_MS,
1250
+ httpFallback = true,
1251
+ } = {}) {
1252
+ return await this.sendKeepSilentAndWaitForAck({
1253
+ deliveryId,
1254
+ sessionKey,
1255
+ reason,
1256
+ source,
1257
+ timeoutMs,
1258
+ httpFallback,
1259
+ });
1260
+ }
1261
+
1225
1262
  async createChatRequest({ fromAgentId, displayName, agentCode, requestContext = {} } = {}) {
1226
1263
  const normalized = normalizeChatRequestInput({ requestContext, source: 'direct_lookup' });
1227
1264
  const normalizedDisplayName = normalizeOptionalText(displayName);
@@ -0,0 +1,67 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import repoPackageJson from '../../package.json' with { type: 'json' };
3
+
4
+ export const CLAWORLD_PLUGIN_PACKAGE_NAME = '@xfxstudio/claworld';
5
+ export const CLAWORLD_PLUGIN_VERSION_HEADER = 'x-claworld-plugin-version';
6
+
7
+ function normalizeText(value, fallback = null) {
8
+ if (value == null) return fallback;
9
+ const normalized = String(value).trim();
10
+ return normalized || fallback;
11
+ }
12
+
13
+ function normalizeHeaderValue(value) {
14
+ if (Array.isArray(value)) {
15
+ return normalizeHeaderValue(value[0]);
16
+ }
17
+ const normalized = normalizeText(value, null);
18
+ if (!normalized) return null;
19
+ return normalized.split(',')[0]?.trim() || null;
20
+ }
21
+
22
+ export function normalizeClaworldPluginVersion(value, fallback = null) {
23
+ const normalized = normalizeText(value, null);
24
+ if (!normalized) return fallback;
25
+ const withoutPrefix = normalized.replace(/^v/i, '');
26
+ if (!/^\d+(?:\.\d+)*(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(withoutPrefix)) {
27
+ return fallback;
28
+ }
29
+ return withoutPrefix;
30
+ }
31
+
32
+ function resolveCurrentPluginVersion() {
33
+ const repoVersion = normalizeClaworldPluginVersion(repoPackageJson?.version, null);
34
+ if (repoPackageJson?.name === CLAWORLD_PLUGIN_PACKAGE_NAME && repoVersion) {
35
+ return repoVersion;
36
+ }
37
+
38
+ try {
39
+ const publishSurfaceSource = readFileSync(
40
+ new URL('../../packages/openclaw-plugin/package.json', import.meta.url),
41
+ 'utf8',
42
+ );
43
+ const publishSurfacePackageJson = JSON.parse(publishSurfaceSource);
44
+ const publishSurfaceVersion = normalizeClaworldPluginVersion(publishSurfacePackageJson?.version, null);
45
+ if (publishSurfacePackageJson?.name === CLAWORLD_PLUGIN_PACKAGE_NAME && publishSurfaceVersion) {
46
+ return publishSurfaceVersion;
47
+ }
48
+ } catch {}
49
+
50
+ return repoVersion || '0.0.0';
51
+ }
52
+
53
+ export const CLAWORLD_PLUGIN_CURRENT_VERSION = resolveCurrentPluginVersion();
54
+
55
+ export function readClaworldPluginVersionFromHeaders(headers = {}) {
56
+ const rawVersion = normalizeHeaderValue(headers?.[CLAWORLD_PLUGIN_VERSION_HEADER]);
57
+ return {
58
+ rawVersion,
59
+ reportedVersion: normalizeClaworldPluginVersion(rawVersion, rawVersion),
60
+ normalizedVersion: normalizeClaworldPluginVersion(rawVersion, null),
61
+ source: rawVersion ? CLAWORLD_PLUGIN_VERSION_HEADER : null,
62
+ };
63
+ }
64
+
65
+ export function buildClaworldRelayClientVersion(version = CLAWORLD_PLUGIN_CURRENT_VERSION) {
66
+ return `claworld-plugin/${normalizeClaworldPluginVersion(version, CLAWORLD_PLUGIN_CURRENT_VERSION)}`;
67
+ }