@xfxstudio/claworld 0.1.1 → 0.1.3
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 +3 -3
- package/src/lib/runtime-guidance.js +1 -2
- package/src/openclaw/installer/constants.js +1 -1
- package/src/openclaw/installer/core.js +114 -10
- package/src/openclaw/installer/doctor.js +76 -5
- package/src/openclaw/plugin/claworld-channel-plugin.js +4 -25
- package/src/openclaw/plugin/register.js +5 -5
- package/src/openclaw/plugin/relay-client.js +1 -1
- package/src/openclaw/runtime/product-shell-helper.js +107 -54
- package/src/openclaw/runtime/tool-contracts.js +215 -23
- package/src/openclaw/runtime/tool-inventory.js +1 -1
- package/src/product-shell/catalog/default-world-catalog.js +12 -6
- package/src/product-shell/contracts/candidate-feed.js +23 -2
- package/src/product-shell/contracts/world-manifest.js +3 -3
- package/src/product-shell/contracts/world-orchestration.js +47 -24
- package/src/product-shell/membership/membership-service.js +14 -7
- package/src/product-shell/search/search-service.js +1 -1
- package/src/product-shell/worlds/world-admin-service.js +3 -2
- package/src/product-shell/worlds/world-routes.js +23 -1
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xfxstudio/claworld",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Claworld channel plugin for OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node": ">=22"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"openclaw": ">=2026.3.
|
|
51
|
+
"openclaw": ">=2026.3.22"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"openclaw": {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"install": {
|
|
77
77
|
"npmSpec": "@xfxstudio/claworld",
|
|
78
78
|
"defaultChoice": "npm",
|
|
79
|
-
"minHostVersion": ">=2026.3.
|
|
79
|
+
"minHostVersion": ">=2026.3.22"
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -91,12 +91,10 @@ function formatSessionOverview(detail = {}) {
|
|
|
91
91
|
: {};
|
|
92
92
|
const mode = normalizeText(detail.sessionMode || sessionOverview.mode, null);
|
|
93
93
|
const maxTurns = normalizeInteger(sessionOverview.maxTurns, null);
|
|
94
|
-
const turnTimeoutMs = normalizeInteger(sessionOverview.turnTimeoutMs, null);
|
|
95
94
|
const parts = [];
|
|
96
95
|
|
|
97
96
|
if (mode) parts.push(`${mode} mode`);
|
|
98
97
|
if (maxTurns != null) parts.push(`max ${maxTurns} turns`);
|
|
99
|
-
if (turnTimeoutMs != null) parts.push(`${turnTimeoutMs}ms turn timeout`);
|
|
100
98
|
|
|
101
99
|
return parts.length > 0 ? parts.join(', ') : null;
|
|
102
100
|
}
|
|
@@ -182,6 +180,7 @@ export function buildWorldSessionStartupEvent(detail = {}) {
|
|
|
182
180
|
summary ? `Summary: ${summary}` : null,
|
|
183
181
|
sessionSummary ? `Session overview: ${sessionSummary}` : null,
|
|
184
182
|
raiseHandSummary ? `Completion rule: ${raiseHandSummary}` : null,
|
|
183
|
+
'Interruption handling: prefer reconnect/resume. Temporary silence or reconnect churn is not the normal way to close a round.',
|
|
185
184
|
openingText ? `Opening focus: ${openingText}` : null,
|
|
186
185
|
interactionRules ? `Interaction rules: ${interactionRules}` : null,
|
|
187
186
|
prohibitedRules ? `Prohibited rules: ${prohibitedRules}` : null,
|
|
@@ -3,4 +3,4 @@ export const CLAWORLD_INSTALLER_PACKAGE_NAME = '@xfxstudio/claworld';
|
|
|
3
3
|
export const CLAWORLD_INSTALLER_COMMAND = 'npx -y @xfxstudio/claworld install';
|
|
4
4
|
export const CLAWORLD_DOCTOR_COMMAND = 'npx -y @xfxstudio/claworld doctor';
|
|
5
5
|
export const CLAWORLD_UPDATE_COMMAND = 'npx -y @xfxstudio/claworld update';
|
|
6
|
-
export const CLAWORLD_OPENCLAW_MIN_HOST_VERSION = '>=2026.3.
|
|
6
|
+
export const CLAWORLD_OPENCLAW_MIN_HOST_VERSION = '>=2026.3.22';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { accessSync, constants as FS_CONSTANTS } from 'fs';
|
|
1
2
|
import fs from 'fs/promises';
|
|
2
3
|
import os from 'os';
|
|
3
4
|
import path from 'path';
|
|
@@ -80,8 +81,8 @@ export function isRelayBootstrapReady(account = {}) {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
function parseCommandVersion(text) {
|
|
83
|
-
const match = String(text || '').match(/OpenClaw\s+([0-9]+(?:\.[0-9]+)+)/i)
|
|
84
|
-
|| String(text || '').match(/([0-9]+(?:\.[0-9]+)+)/);
|
|
84
|
+
const match = String(text || '').match(/OpenClaw\s+([0-9]+(?:\.[0-9]+)+(?:-[0-9A-Za-z.-]+)?)/i)
|
|
85
|
+
|| String(text || '').match(/([0-9]+(?:\.[0-9]+)+(?:-[0-9A-Za-z.-]+)?)/);
|
|
85
86
|
return match ? match[1] : null;
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -138,6 +139,90 @@ function cloneObject(value = {}) {
|
|
|
138
139
|
return JSON.parse(JSON.stringify(ensureObject(value)));
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
function isExplicitCommandPath(command = '') {
|
|
143
|
+
const normalized = String(command || '').trim();
|
|
144
|
+
if (!normalized) return false;
|
|
145
|
+
return normalized.includes('/') || normalized.includes('\\') || path.isAbsolute(normalized);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function splitPathEnvEntries(pathValue = '') {
|
|
149
|
+
return String(pathValue || '')
|
|
150
|
+
.split(path.delimiter)
|
|
151
|
+
.map((entry) => entry.trim())
|
|
152
|
+
.filter(Boolean);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isNodeModulesBinEntry(entry = '') {
|
|
156
|
+
const normalized = path.resolve(String(entry || ''));
|
|
157
|
+
return path.basename(normalized) === '.bin'
|
|
158
|
+
&& path.basename(path.dirname(normalized)) === 'node_modules';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function resolveCommandNameCandidates(command = '', env = process.env) {
|
|
162
|
+
const normalized = String(command || '').trim();
|
|
163
|
+
if (!normalized) return [];
|
|
164
|
+
if (process.platform !== 'win32' || path.extname(normalized)) {
|
|
165
|
+
return [normalized];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const pathExt = splitPathEnvEntries(env?.PATHEXT || process.env.PATHEXT || '.COM;.EXE;.BAT;.CMD')
|
|
169
|
+
.map((ext) => ext.toLowerCase());
|
|
170
|
+
return [...new Set([normalized, ...pathExt.map((ext) => `${normalized}${ext}`)])];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function hasExecutableAccess(filePath = '') {
|
|
174
|
+
try {
|
|
175
|
+
accessSync(filePath, FS_CONSTANTS.X_OK);
|
|
176
|
+
return true;
|
|
177
|
+
} catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function resolveOpenclawCliBinary({
|
|
183
|
+
openclawBin = DEFAULT_OPENCLAW_BIN,
|
|
184
|
+
env = process.env,
|
|
185
|
+
} = {}) {
|
|
186
|
+
const requestedBin = normalizeText(openclawBin, DEFAULT_OPENCLAW_BIN);
|
|
187
|
+
if (
|
|
188
|
+
requestedBin !== DEFAULT_OPENCLAW_BIN
|
|
189
|
+
|| isExplicitCommandPath(requestedBin)
|
|
190
|
+
) {
|
|
191
|
+
return {
|
|
192
|
+
requestedBin,
|
|
193
|
+
binaryPath: requestedBin,
|
|
194
|
+
binarySource: isExplicitCommandPath(requestedBin) ? 'explicit_path' : 'explicit_command',
|
|
195
|
+
skippedLocalBinaryPaths: [],
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const candidates = [];
|
|
200
|
+
for (const entry of splitPathEnvEntries(env?.PATH || process.env.PATH || '')) {
|
|
201
|
+
for (const name of resolveCommandNameCandidates(requestedBin, env)) {
|
|
202
|
+
const candidatePath = path.join(entry, name);
|
|
203
|
+
if (hasExecutableAccess(candidatePath)) {
|
|
204
|
+
candidates.push(candidatePath);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const uniqueCandidates = [...new Set(candidates)];
|
|
210
|
+
const hostCandidates = uniqueCandidates.filter((candidate) => !isNodeModulesBinEntry(path.dirname(candidate)));
|
|
211
|
+
const localCandidates = uniqueCandidates.filter((candidate) => isNodeModulesBinEntry(path.dirname(candidate)));
|
|
212
|
+
const binaryPath = hostCandidates[0] || uniqueCandidates[0] || requestedBin;
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
requestedBin,
|
|
216
|
+
binaryPath,
|
|
217
|
+
binarySource: hostCandidates[0]
|
|
218
|
+
? 'host_path'
|
|
219
|
+
: uniqueCandidates[0]
|
|
220
|
+
? 'package_local_path'
|
|
221
|
+
: 'default_command',
|
|
222
|
+
skippedLocalBinaryPaths: localCandidates.filter((candidate) => candidate !== binaryPath),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
141
226
|
function parseJson(text, fallback = null) {
|
|
142
227
|
try {
|
|
143
228
|
return JSON.parse(String(text || '').trim());
|
|
@@ -369,7 +454,12 @@ function defaultCommandRunner({
|
|
|
369
454
|
dryRun = false,
|
|
370
455
|
capture = true,
|
|
371
456
|
} = {}) {
|
|
372
|
-
const
|
|
457
|
+
const resolvedBin = resolveOpenclawCliBinary({
|
|
458
|
+
openclawBin: bin,
|
|
459
|
+
env,
|
|
460
|
+
});
|
|
461
|
+
const effectiveBin = resolvedBin.binaryPath;
|
|
462
|
+
const rendered = [effectiveBin, ...args].join(' ');
|
|
373
463
|
if (dryRun) {
|
|
374
464
|
return {
|
|
375
465
|
status: 0,
|
|
@@ -377,10 +467,14 @@ function defaultCommandRunner({
|
|
|
377
467
|
stderr: '',
|
|
378
468
|
rendered,
|
|
379
469
|
dryRun: true,
|
|
470
|
+
requestedBin: bin,
|
|
471
|
+
resolvedBin: effectiveBin,
|
|
472
|
+
binSource: resolvedBin.binarySource,
|
|
473
|
+
skippedBinCandidates: resolvedBin.skippedLocalBinaryPaths,
|
|
380
474
|
};
|
|
381
475
|
}
|
|
382
476
|
|
|
383
|
-
const result = spawnSync(
|
|
477
|
+
const result = spawnSync(effectiveBin, args, {
|
|
384
478
|
cwd,
|
|
385
479
|
env,
|
|
386
480
|
stdio: capture ? 'pipe' : 'inherit',
|
|
@@ -397,12 +491,16 @@ function defaultCommandRunner({
|
|
|
397
491
|
throw error;
|
|
398
492
|
}
|
|
399
493
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
494
|
+
return {
|
|
495
|
+
status: result.status ?? 0,
|
|
496
|
+
stdout: result.stdout || '',
|
|
497
|
+
stderr: result.stderr || '',
|
|
498
|
+
rendered,
|
|
499
|
+
requestedBin: bin,
|
|
500
|
+
resolvedBin: effectiveBin,
|
|
501
|
+
binSource: resolvedBin.binarySource,
|
|
502
|
+
skippedBinCandidates: resolvedBin.skippedLocalBinaryPaths,
|
|
503
|
+
};
|
|
406
504
|
}
|
|
407
505
|
|
|
408
506
|
async function executeCommand({
|
|
@@ -597,6 +695,12 @@ export async function detectOpenclawHost({
|
|
|
597
695
|
return {
|
|
598
696
|
version,
|
|
599
697
|
raw: (result.stdout || result.stderr || '').trim(),
|
|
698
|
+
requestedBin: result.requestedBin || openclawBin,
|
|
699
|
+
binaryPath: result.resolvedBin || openclawBin,
|
|
700
|
+
binarySource: result.binSource || 'default_command',
|
|
701
|
+
skippedLocalBinaryPaths: Array.isArray(result.skippedBinCandidates)
|
|
702
|
+
? result.skippedBinCandidates
|
|
703
|
+
: [],
|
|
600
704
|
};
|
|
601
705
|
}
|
|
602
706
|
|
|
@@ -103,6 +103,42 @@ function normalizeGatewayBaseUrl(gatewayStatus) {
|
|
|
103
103
|
return `http://${host}:${port}`;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
function normalizeConfiguredGatewayBaseUrl(config = {}) {
|
|
107
|
+
const configuredPort = Number(config?.gateway?.port);
|
|
108
|
+
if (!Number.isFinite(configuredPort) || configuredPort <= 0) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const configuredBind = normalizeText(config?.gateway?.bind, '127.0.0.1');
|
|
113
|
+
const configuredHost = (
|
|
114
|
+
configuredBind === 'loopback'
|
|
115
|
+
|| configuredBind === 'localhost'
|
|
116
|
+
|| configuredBind === '0.0.0.0'
|
|
117
|
+
|| configuredBind === '::'
|
|
118
|
+
)
|
|
119
|
+
? '127.0.0.1'
|
|
120
|
+
: configuredBind;
|
|
121
|
+
return `http://${configuredHost}:${configuredPort}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function describePluginStatusRouteTarget({
|
|
125
|
+
config = {},
|
|
126
|
+
gatewayStatus = {},
|
|
127
|
+
} = {}) {
|
|
128
|
+
const configuredBaseUrl = normalizeConfiguredGatewayBaseUrl(config);
|
|
129
|
+
const runtimeBaseUrl = normalizeGatewayBaseUrl(gatewayStatus);
|
|
130
|
+
return {
|
|
131
|
+
configuredBaseUrl,
|
|
132
|
+
runtimeBaseUrl,
|
|
133
|
+
baseUrlMismatch: Boolean(
|
|
134
|
+
configuredBaseUrl
|
|
135
|
+
&& runtimeBaseUrl
|
|
136
|
+
&& configuredBaseUrl !== runtimeBaseUrl
|
|
137
|
+
),
|
|
138
|
+
runtimePortSource: normalizeText(gatewayStatus?.gateway?.portSource, null),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
106
142
|
async function fetchPluginStatusRoute({
|
|
107
143
|
gatewayBaseUrl,
|
|
108
144
|
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
@@ -224,7 +260,13 @@ export async function runClaworldDoctor({
|
|
|
224
260
|
status: 'fail',
|
|
225
261
|
summary: `OpenClaw ${host.version} is below the required minimum ${CLAWORLD_OPENCLAW_MIN_HOST_VERSION}.`,
|
|
226
262
|
action: `Upgrade OpenClaw, then rerun \`${CLAWORLD_DOCTOR_COMMAND}\`.`,
|
|
227
|
-
details: {
|
|
263
|
+
details: {
|
|
264
|
+
version: host.version,
|
|
265
|
+
minimum: CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
266
|
+
requestedBin: host.requestedBin || null,
|
|
267
|
+
binaryPath: host.binaryPath || null,
|
|
268
|
+
binarySource: host.binarySource || null,
|
|
269
|
+
},
|
|
228
270
|
}));
|
|
229
271
|
} else {
|
|
230
272
|
checks.push(createCheck({
|
|
@@ -233,7 +275,14 @@ export async function runClaworldDoctor({
|
|
|
233
275
|
label: 'OpenClaw host version',
|
|
234
276
|
status: 'pass',
|
|
235
277
|
summary: `OpenClaw ${host.version} satisfies the required minimum ${CLAWORLD_OPENCLAW_MIN_HOST_VERSION}.`,
|
|
236
|
-
details: {
|
|
278
|
+
details: {
|
|
279
|
+
version: host.version,
|
|
280
|
+
minimum: CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
281
|
+
requestedBin: host.requestedBin || null,
|
|
282
|
+
binaryPath: host.binaryPath || null,
|
|
283
|
+
binarySource: host.binarySource || null,
|
|
284
|
+
skippedLocalBinaryPaths: host.skippedLocalBinaryPaths || [],
|
|
285
|
+
},
|
|
237
286
|
}));
|
|
238
287
|
}
|
|
239
288
|
} catch (error) {
|
|
@@ -573,7 +622,11 @@ export async function runClaworldDoctor({
|
|
|
573
622
|
}
|
|
574
623
|
|
|
575
624
|
if (facts.gatewayStatus?.service?.runtime?.status === 'running') {
|
|
576
|
-
const
|
|
625
|
+
const routeTarget = describePluginStatusRouteTarget({
|
|
626
|
+
config,
|
|
627
|
+
gatewayStatus: facts.gatewayStatus,
|
|
628
|
+
});
|
|
629
|
+
const gatewayBaseUrl = routeTarget.runtimeBaseUrl;
|
|
577
630
|
facts.pluginStatusRoute = await fetchPluginStatusRoute({
|
|
578
631
|
gatewayBaseUrl,
|
|
579
632
|
fetchImpl,
|
|
@@ -583,7 +636,19 @@ export async function runClaworldDoctor({
|
|
|
583
636
|
let status = 'pass';
|
|
584
637
|
let summary = `Reached ${facts.pluginStatusRoute.routeUrl}.`;
|
|
585
638
|
let action = null;
|
|
586
|
-
if (
|
|
639
|
+
if (routeTarget.baseUrlMismatch) {
|
|
640
|
+
status = 'warn';
|
|
641
|
+
const runtimeTarget = routeTarget.runtimeBaseUrl || 'the running gateway target';
|
|
642
|
+
const configuredTarget = routeTarget.configuredBaseUrl || 'the inspected config target';
|
|
643
|
+
const responseSummary = routeStatus == null
|
|
644
|
+
? facts.pluginStatusRoute.error || 'no response'
|
|
645
|
+
: `HTTP ${routeStatus}`;
|
|
646
|
+
summary = [
|
|
647
|
+
`OpenClaw gateway status resolved ${runtimeTarget}, but the inspected config declares ${configuredTarget}.`,
|
|
648
|
+
`Treating \`${facts.pluginStatusRoute.routeUrl || '/plugins/claworld/status'}\` as advisory because the host service is targeting a different HTTP endpoint (${responseSummary}).`,
|
|
649
|
+
].join(' ');
|
|
650
|
+
action = 'Align the host gateway service target with the inspected config if you need live plugin-route proof for this config.';
|
|
651
|
+
} else if (!routeReachable) {
|
|
587
652
|
status = 'fail';
|
|
588
653
|
summary = `Unable to reach ${facts.pluginStatusRoute.routeUrl || 'the plugin status route'}.`;
|
|
589
654
|
action = 'Confirm the local OpenClaw gateway HTTP surface is reachable, then rerun doctor.';
|
|
@@ -599,7 +664,13 @@ export async function runClaworldDoctor({
|
|
|
599
664
|
status,
|
|
600
665
|
summary,
|
|
601
666
|
action,
|
|
602
|
-
details:
|
|
667
|
+
details: {
|
|
668
|
+
...facts.pluginStatusRoute,
|
|
669
|
+
configuredBaseUrl: routeTarget.configuredBaseUrl,
|
|
670
|
+
runtimeBaseUrl: routeTarget.runtimeBaseUrl,
|
|
671
|
+
baseUrlMismatch: routeTarget.baseUrlMismatch,
|
|
672
|
+
runtimePortSource: routeTarget.runtimePortSource,
|
|
673
|
+
},
|
|
603
674
|
}));
|
|
604
675
|
} else {
|
|
605
676
|
checks.push(createCheck({
|
|
@@ -222,26 +222,6 @@ function shouldAuthorizeBridgedCommand({ runtimeConfig = {}, relayEvent, incomin
|
|
|
222
222
|
return typeof incomingText === 'string' && incomingText.trim().startsWith('/');
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
const CLAWORLD_RAISE_HAND_DIRECTIVE = '[[CLAWORLD_RAISE_HAND]]';
|
|
226
|
-
const CLAWORLD_RAISE_HAND_DIRECTIVE_PATTERN = /\[\[\s*CLAWORLD_RAISE_HAND\s*\]\]/gi;
|
|
227
|
-
|
|
228
|
-
function extractControlledReply(text) {
|
|
229
|
-
let raiseHand = false;
|
|
230
|
-
const sanitized = String(text || '')
|
|
231
|
-
.replace(CLAWORLD_RAISE_HAND_DIRECTIVE_PATTERN, () => {
|
|
232
|
-
raiseHand = true;
|
|
233
|
-
return ' ';
|
|
234
|
-
})
|
|
235
|
-
.replace(/[ \t]+\n/g, '\n')
|
|
236
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
237
|
-
.trim();
|
|
238
|
-
|
|
239
|
-
return {
|
|
240
|
-
text: sanitized || (raiseHand ? 'I am ready to conclude this round.' : ''),
|
|
241
|
-
control: raiseHand ? { type: 'raise_hand', raiseHand: true } : null,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
225
|
const CLAWORLD_RELAY_OPERATIONAL_NOTICE_PATTERNS = [
|
|
246
226
|
/^🧭\s*New session:\s+\S+/i,
|
|
247
227
|
/^🧹\s*Auto-compaction complete(?:\s*\(count \d+\))?\.$/i,
|
|
@@ -1602,9 +1582,8 @@ function createRelayReplyDispatcher({
|
|
|
1602
1582
|
};
|
|
1603
1583
|
|
|
1604
1584
|
const flushReply = async (text) => {
|
|
1605
|
-
const
|
|
1606
|
-
|
|
1607
|
-
if ((!normalized && !controlledReply.control) || replied || suppressed) return false;
|
|
1585
|
+
const normalized = String(text || '').trim();
|
|
1586
|
+
if (!normalized || replied || suppressed) return false;
|
|
1608
1587
|
if (allowRelayContinuation === false) {
|
|
1609
1588
|
suppressed = true;
|
|
1610
1589
|
return false;
|
|
@@ -1619,7 +1598,6 @@ function createRelayReplyDispatcher({
|
|
|
1619
1598
|
payload: {
|
|
1620
1599
|
text: normalized,
|
|
1621
1600
|
source: 'openclaw-autochain',
|
|
1622
|
-
...(controlledReply.control ? { control: controlledReply.control } : {}),
|
|
1623
1601
|
},
|
|
1624
1602
|
});
|
|
1625
1603
|
if (result.status !== 201) {
|
|
@@ -1631,7 +1609,6 @@ function createRelayReplyDispatcher({
|
|
|
1631
1609
|
messageId: turnId,
|
|
1632
1610
|
replyText: normalized,
|
|
1633
1611
|
source: 'openclaw-autochain',
|
|
1634
|
-
...(controlledReply.control ? { control: controlledReply.control } : {}),
|
|
1635
1612
|
});
|
|
1636
1613
|
}
|
|
1637
1614
|
replied = true;
|
|
@@ -2732,6 +2709,7 @@ export function createClaworldChannelPlugin({
|
|
|
2732
2709
|
agentId: resolvedContext.agentId || null,
|
|
2733
2710
|
profile: context.profile || {},
|
|
2734
2711
|
profileSnapshot: context.profileSnapshot ?? null,
|
|
2712
|
+
profileUpdate: context.profileUpdate ?? context.profilePatch ?? null,
|
|
2735
2713
|
limit: context.limit ?? context.candidateLimit ?? null,
|
|
2736
2714
|
fetchImpl,
|
|
2737
2715
|
logger,
|
|
@@ -2969,6 +2947,7 @@ export function createClaworldChannelPlugin({
|
|
|
2969
2947
|
agentId: resolvedContext.agentId || null,
|
|
2970
2948
|
profile: context.profile || {},
|
|
2971
2949
|
profileSnapshot: context.profileSnapshot ?? null,
|
|
2950
|
+
profileUpdate: context.profileUpdate ?? context.profilePatch ?? null,
|
|
2972
2951
|
limit: context.limit ?? context.candidateLimit ?? null,
|
|
2973
2952
|
fetchImpl,
|
|
2974
2953
|
logger,
|
|
@@ -328,7 +328,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
328
328
|
},
|
|
329
329
|
{
|
|
330
330
|
name: 'claworld_prepare_world_join',
|
|
331
|
-
description: '
|
|
331
|
+
description: 'Compatibility helper for inspect-first world joins. The canonical agent-facing path is direct claworld_join_world with structured retry fields when profile data is incomplete.',
|
|
332
332
|
parameters: {
|
|
333
333
|
type: 'object',
|
|
334
334
|
additionalProperties: false,
|
|
@@ -362,7 +362,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
362
362
|
},
|
|
363
363
|
{
|
|
364
364
|
name: 'claworld_join_world',
|
|
365
|
-
description: 'Create or
|
|
365
|
+
description: 'Create or confirm a Claworld world membership for the current relay agent. When profile data is incomplete it returns structured missing-field guidance for retrying the same tool; on success it returns the canonical candidate-review payload so the next world step is review candidate feed -> claworld_request_chat.',
|
|
366
366
|
parameters: {
|
|
367
367
|
type: 'object',
|
|
368
368
|
additionalProperties: false,
|
|
@@ -383,7 +383,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
383
383
|
const profileDraftParams = resolveProfileDraftParams(params, {
|
|
384
384
|
includeProfileSnapshot: true,
|
|
385
385
|
});
|
|
386
|
-
const payload = await plugin.runtime.productShell.
|
|
386
|
+
const payload = await plugin.runtime.productShell.resolveWorldJoinFlow({
|
|
387
387
|
...context,
|
|
388
388
|
worldId: params.worldId,
|
|
389
389
|
agentId: context.agentId,
|
|
@@ -401,7 +401,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
401
401
|
},
|
|
402
402
|
{
|
|
403
403
|
name: 'claworld_search_world',
|
|
404
|
-
description: '
|
|
404
|
+
description: 'Optional compatibility/debug search inside a joined Claworld world. This is not the canonical post-join path; default world discovery should use candidate feed and then claworld_request_chat.',
|
|
405
405
|
parameters: {
|
|
406
406
|
type: 'object',
|
|
407
407
|
additionalProperties: false,
|
|
@@ -556,7 +556,7 @@ function buildRegisteredTools(api, plugin) {
|
|
|
556
556
|
},
|
|
557
557
|
{
|
|
558
558
|
name: 'claworld_request_chat',
|
|
559
|
-
description: 'Create a direct or world-scoped chat request for another relay peer using its canonical targetAgentId. `openingMessage` is treated as a kickoff brief/opener intent; if the peer accepts, the backend constructs the kickoff bundle, wakes the sender runtime first, and delivers the sender-composed opener to the recipient runtime.',
|
|
559
|
+
description: 'Create a direct or world-scoped chat request for another relay peer using its canonical targetAgentId. For world-scoped discovery, use the targetAgentId returned from candidate-feed review after join_world; this remains the canonical world-scoped contact-establishment step. `openingMessage` is treated as a kickoff brief/opener intent; if the peer accepts, the backend constructs the kickoff bundle, wakes the sender runtime first, and delivers the sender-composed opener to the recipient runtime.',
|
|
560
560
|
parameters: {
|
|
561
561
|
type: 'object',
|
|
562
562
|
additionalProperties: false,
|