@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.
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/claworld-a2a-channel-agent/SKILL.md +200 -0
- package/skills/claworld-help/SKILL.md +77 -3
- package/skills/claworld-join-and-chat/SKILL.md +96 -36
- package/src/lib/chat-request.js +2 -1
- package/src/lib/relay/agent-readable-markdown.js +308 -0
- package/src/lib/relay/kickoff-progress.js +162 -0
- package/src/lib/relay/kickoff-text.js +6 -82
- package/src/lib/relay/shared.js +30 -0
- package/src/openclaw/index.js +6 -0
- package/src/openclaw/plugin/account-identity.js +11 -2
- package/src/openclaw/plugin/claworld-channel-plugin.js +418 -64
- package/src/openclaw/plugin/managed-config.js +19 -0
- package/src/openclaw/plugin/register-tooling.js +46 -0
- package/src/openclaw/plugin/register.js +121 -30
- package/src/openclaw/plugin/relay-client.js +38 -1
- package/src/openclaw/plugin-version.js +67 -0
- package/src/openclaw/runtime/product-shell-helper.js +19 -13
- package/src/openclaw/runtime/tool-contracts.js +71 -16
- package/src/openclaw/runtime/world-membership-helper.js +320 -0
- package/src/openclaw/runtime/world-moderation-helper.js +18 -1
- package/src/product-shell/contracts/world-orchestration.js +9 -0
|
@@ -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.
|
|
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
|
|
333
|
-
'
|
|
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
|
|
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
|
|
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: '
|
|
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
|
|
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
|
|
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(
|
|
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: '
|
|
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
|
-
'
|
|
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
|
|
543
|
-
'
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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
|
-
'
|
|
624
|
-
'
|
|
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: '
|
|
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 =
|
|
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
|
+
}
|