@xfxstudio/claworld 0.2.8 → 0.2.10-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/openclaw.plugin.json +7 -63
- package/package.json +6 -2
- package/skills/claworld-help/SKILL.md +7 -3
- package/skills/claworld-join-and-chat/SKILL.md +38 -9
- package/skills/claworld-manage-worlds/SKILL.md +81 -10
- package/src/lib/agent-profile.js +8 -3
- package/src/lib/chat-request.js +19 -1
- package/src/lib/policy.js +2 -6
- package/src/lib/public-identity.js +175 -0
- package/src/lib/relay/kickoff-text.js +7 -1
- package/src/openclaw/installer/cli.js +46 -1
- package/src/openclaw/installer/constants.js +1 -0
- package/src/openclaw/installer/core.js +234 -3
- package/src/openclaw/installer/doctor.js +2 -2
- package/src/openclaw/plugin/account-identity.js +1 -2
- package/src/openclaw/plugin/claworld-channel-plugin.js +302 -266
- package/src/openclaw/plugin/config-schema.js +9 -23
- package/src/openclaw/plugin/managed-config.js +284 -79
- package/src/openclaw/plugin/onboarding.js +22 -42
- package/src/openclaw/plugin/register.js +144 -25
- package/src/openclaw/plugin/relay-client.js +237 -18
- package/src/openclaw/runtime/backend-error-context.js +91 -0
- package/src/openclaw/runtime/feedback-helper.js +1 -2
- package/src/openclaw/runtime/product-shell-helper.js +43 -9
- package/src/openclaw/runtime/tool-contracts.js +65 -3
- package/src/openclaw/runtime/tool-inventory.js +8 -1
- package/src/openclaw/runtime/world-moderation-helper.js +3 -19
- package/src/product-shell/contracts/candidate-feed.js +7 -0
- package/src/product-shell/contracts/world-manifest.js +0 -1
- package/src/product-shell/contracts/world-orchestration.js +10 -1
- package/src/product-shell/conversation-feedback/conversation-feedback-service.js +261 -0
- package/src/product-shell/feedback/feedback-routes.js +0 -1
- package/src/product-shell/feedback/feedback-service.js +4 -9
- package/src/product-shell/index.js +40 -7
- package/src/product-shell/matching/matchmaking-service.js +22 -1
- package/src/product-shell/membership/membership-service.js +5 -1
- package/src/product-shell/onboarding/onboarding-service.js +10 -21
- package/src/product-shell/profile/public-identity-routes.js +60 -0
- package/src/product-shell/profile/public-identity-service.js +190 -0
- package/src/product-shell/search/search-service.js +9 -2
- package/src/product-shell/social/chat-request-routes.js +4 -1
- package/src/product-shell/social/chat-request-service.js +184 -22
- package/src/product-shell/social/friend-routes.js +1 -1
- package/src/product-shell/social/friend-service.js +16 -19
- package/src/product-shell/social/social-routes.js +2 -2
- package/src/product-shell/social/social-service.js +31 -35
- package/src/product-shell/worlds/world-admin-service.js +31 -10
- package/src/product-shell/worlds/world-broadcast-service.js +2 -2
- package/src/lib/agent-address.js +0 -46
|
@@ -45,12 +45,14 @@ import {
|
|
|
45
45
|
resolveWorldSelection,
|
|
46
46
|
resolveWorldSelectionFlow,
|
|
47
47
|
} from '../runtime/product-shell-helper.js';
|
|
48
|
+
import { extractBackendErrorContext } from '../runtime/backend-error-context.js';
|
|
48
49
|
import { getClaworldRuntime } from './runtime.js';
|
|
49
50
|
import {
|
|
50
51
|
createRuntimeBoundaryError,
|
|
51
52
|
normalizeRuntimeBoundaryError,
|
|
52
53
|
serializeRuntimeBoundaryError,
|
|
53
54
|
} from '../../lib/runtime-errors.js';
|
|
55
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
54
56
|
|
|
55
57
|
function normalizeRelayHttpBaseUrl(serverUrl) {
|
|
56
58
|
const parsed = new URL(serverUrl);
|
|
@@ -67,108 +69,16 @@ function normalizePluginOptionalText(value) {
|
|
|
67
69
|
return normalized || null;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
const atIndex = defaultToAddress.indexOf('@');
|
|
73
|
-
if (atIndex > 0 && atIndex < defaultToAddress.length - 1) {
|
|
74
|
-
return defaultToAddress.slice(atIndex + 1).trim().toLowerCase();
|
|
75
|
-
}
|
|
76
|
-
return 'relay.local';
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const RELAY_LOCAL_AGENT_CODE_PATTERN = /^[A-Za-z0-9._:+~-]+$/;
|
|
80
|
-
const RELAY_CANONICAL_AGENT_CODE_PATTERN = /^[A-Za-z0-9._:+~-]+@[A-Za-z0-9._:+~-]+$/;
|
|
81
|
-
|
|
82
|
-
function normalizeRelayDomainName(value, fallback = null) {
|
|
83
|
-
const normalized = normalizeClaworldText(value, fallback)?.toLowerCase() || null;
|
|
84
|
-
if (!normalized) return fallback;
|
|
85
|
-
if (!/^[a-z0-9._:+~-]+$/.test(normalized)) return fallback;
|
|
86
|
-
return normalized;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function normalizeRelayLocalAgentCode(value, fallback = null) {
|
|
90
|
-
const normalized = normalizeClaworldText(value, fallback)?.toLowerCase() || null;
|
|
91
|
-
if (!normalized) return fallback;
|
|
92
|
-
if (!RELAY_LOCAL_AGENT_CODE_PATTERN.test(normalized)) return fallback;
|
|
93
|
-
return normalized;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function parseCanonicalRelayAgentCode(value) {
|
|
97
|
-
const normalized = normalizeClaworldText(value, null)?.toLowerCase() || null;
|
|
98
|
-
if (!normalized || !RELAY_CANONICAL_AGENT_CODE_PATTERN.test(normalized)) return null;
|
|
99
|
-
const atIndex = normalized.indexOf('@');
|
|
100
|
-
if (atIndex <= 0 || atIndex >= normalized.length - 1) return null;
|
|
101
|
-
const relayLocalCode = normalizeRelayLocalAgentCode(normalized.slice(0, atIndex), null);
|
|
102
|
-
const domain = normalizeRelayDomainName(normalized.slice(atIndex + 1), null);
|
|
103
|
-
if (!relayLocalCode || !domain) return null;
|
|
104
|
-
return {
|
|
105
|
-
agentCode: `${relayLocalCode}@${domain}`,
|
|
106
|
-
relayLocalCode,
|
|
107
|
-
domain,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function buildCanonicalRelayAgentCode(relayLocalCode, runtimeConfig = {}, domainOverride = null) {
|
|
112
|
-
const normalizedRelayLocalCode = normalizeRelayLocalAgentCode(relayLocalCode, null);
|
|
113
|
-
const domain = normalizeRelayDomainName(domainOverride, null)
|
|
114
|
-
|| normalizeRelayDomainName(inferRelayDomain(runtimeConfig), null);
|
|
115
|
-
if (!normalizedRelayLocalCode || !domain) return null;
|
|
116
|
-
return `${normalizedRelayLocalCode}@${domain}`;
|
|
72
|
+
function resolveClientMessageId(value = null) {
|
|
73
|
+
return normalizePluginOptionalText(value) || `cmsg_${uuidv4()}`;
|
|
117
74
|
}
|
|
118
75
|
|
|
119
|
-
function
|
|
120
|
-
const parsed = parseCanonicalRelayAgentCode(value);
|
|
121
|
-
if (parsed) return parsed.agentCode;
|
|
122
|
-
const relayLocalCode = normalizeRelayLocalAgentCode(value, null);
|
|
123
|
-
if (!relayLocalCode) return null;
|
|
124
|
-
return buildCanonicalRelayAgentCode(relayLocalCode, runtimeConfig);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function normalizeRelayIdentityInput({ runtimeConfig = {}, agentId = null, agentCode = null, address = null } = {}) {
|
|
128
|
-
const normalizedAgentId = normalizeClaworldText(agentId, null);
|
|
129
|
-
const normalizedAddress = normalizeClaworldText(resolveRelayAddress(address || agentCode || '', runtimeConfig), null)?.toLowerCase() || null;
|
|
130
|
-
const parsedCanonicalAgentCode = parseCanonicalRelayAgentCode(agentCode)
|
|
131
|
-
|| parseCanonicalRelayAgentCode(normalizedAddress);
|
|
132
|
-
const relayLocalCode = normalizeRelayLocalAgentCode(agentCode, null)
|
|
133
|
-
|| parsedCanonicalAgentCode?.relayLocalCode
|
|
134
|
-
|| null;
|
|
135
|
-
const domain = parsedCanonicalAgentCode?.domain
|
|
136
|
-
|| normalizeRelayDomainName(normalizedAddress?.split('@')[1], null)
|
|
137
|
-
|| normalizeRelayDomainName(inferRelayDomain(runtimeConfig), null);
|
|
138
|
-
const normalizedAgentCode = parsedCanonicalAgentCode?.agentCode
|
|
139
|
-
|| (relayLocalCode ? buildCanonicalRelayAgentCode(relayLocalCode, runtimeConfig, domain) : null)
|
|
140
|
-
|| null;
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
agentId: normalizedAgentId,
|
|
144
|
-
agentCode: normalizedAgentCode,
|
|
145
|
-
relayLocalCode,
|
|
146
|
-
address: normalizedAddress || normalizedAgentCode || null,
|
|
147
|
-
domain,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function buildRelayAgentSummary(item = {}, runtimeConfig = {}) {
|
|
76
|
+
function buildRelayAgentSummary(item = {}) {
|
|
152
77
|
const normalizedAgentId = normalizeClaworldText(item?.agentId, null);
|
|
153
|
-
const relayLocalCode = normalizeRelayLocalAgentCode(item?.agentCode, null);
|
|
154
|
-
const address = normalizeClaworldText(item?.address, null)?.toLowerCase()
|
|
155
|
-
|| buildCanonicalRelayAgentCode(relayLocalCode, runtimeConfig, item?.domain)
|
|
156
|
-
|| null;
|
|
157
|
-
const parsedCanonicalAgentCode = parseCanonicalRelayAgentCode(address);
|
|
158
|
-
const domain = normalizeRelayDomainName(item?.domain, null)
|
|
159
|
-
|| parsedCanonicalAgentCode?.domain
|
|
160
|
-
|| normalizeRelayDomainName(inferRelayDomain(runtimeConfig), null);
|
|
161
|
-
const canonicalAgentCode = parsedCanonicalAgentCode?.agentCode
|
|
162
|
-
|| buildCanonicalRelayAgentCode(relayLocalCode, runtimeConfig, domain)
|
|
163
|
-
|| null;
|
|
164
|
-
|
|
165
78
|
return {
|
|
166
79
|
agentId: normalizedAgentId,
|
|
167
|
-
agentCode: canonicalAgentCode,
|
|
168
|
-
relayLocalCode: relayLocalCode || parsedCanonicalAgentCode?.relayLocalCode || null,
|
|
169
|
-
domain,
|
|
170
|
-
address: address || canonicalAgentCode || null,
|
|
171
80
|
displayName: normalizeClaworldText(item?.displayName, null),
|
|
81
|
+
publicIdentity: item?.publicIdentity && typeof item.publicIdentity === 'object' ? item.publicIdentity : null,
|
|
172
82
|
discoverable: typeof item?.discoverable === 'boolean' ? item.discoverable : null,
|
|
173
83
|
contactable: typeof item?.contactable === 'boolean' ? item.contactable : null,
|
|
174
84
|
online: typeof item?.online === 'boolean' ? item.online : null,
|
|
@@ -179,19 +89,10 @@ function normalizeClaworldTarget(raw) {
|
|
|
179
89
|
if (typeof raw !== 'string') return undefined;
|
|
180
90
|
let value = raw.trim();
|
|
181
91
|
if (!value) return undefined;
|
|
182
|
-
value = value.replace(/^claworld:/i, '').replace(/^user:/i, '').
|
|
92
|
+
value = value.replace(/^claworld:/i, '').replace(/^user:/i, '').trim();
|
|
183
93
|
return value || undefined;
|
|
184
94
|
}
|
|
185
95
|
|
|
186
|
-
function resolveRelayAddress(to, runtimeConfig = {}) {
|
|
187
|
-
const normalized = normalizeClaworldTarget(typeof to === 'string' ? to : '');
|
|
188
|
-
const fallback = normalizeClaworldTarget(runtimeConfig.relay?.defaultToAddress || '');
|
|
189
|
-
const candidate = normalized || fallback;
|
|
190
|
-
if (!candidate) return '';
|
|
191
|
-
if (candidate.includes('@')) return candidate.toLowerCase();
|
|
192
|
-
return `${candidate.toLowerCase()}@${inferRelayDomain(runtimeConfig)}`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
96
|
function normalizeClaworldText(value, fallback = null) {
|
|
196
97
|
if (value == null) return fallback;
|
|
197
98
|
const normalized = String(value).trim();
|
|
@@ -215,6 +116,45 @@ function shouldAuthorizeBridgedCommand({ runtimeConfig = {}, incomingText }) {
|
|
|
215
116
|
return typeof incomingText === 'string' && incomingText.trim().startsWith('/');
|
|
216
117
|
}
|
|
217
118
|
|
|
119
|
+
function normalizeUntrustedContextLines(value) {
|
|
120
|
+
if (Array.isArray(value)) {
|
|
121
|
+
return value
|
|
122
|
+
.map((entry) => resolveNormalizedText(entry, null))
|
|
123
|
+
.filter(Boolean);
|
|
124
|
+
}
|
|
125
|
+
const singleLine = resolveNormalizedText(value, null);
|
|
126
|
+
return singleLine ? [singleLine] : [];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function mergeUntrustedContextLines(...groups) {
|
|
130
|
+
const merged = [];
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
for (const group of groups) {
|
|
133
|
+
for (const line of normalizeUntrustedContextLines(group)) {
|
|
134
|
+
if (seen.has(line)) continue;
|
|
135
|
+
seen.add(line);
|
|
136
|
+
merged.push(line);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return merged;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function parseBridgeTimestampMs(value) {
|
|
143
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
144
|
+
if (typeof value !== 'string') return null;
|
|
145
|
+
const normalized = value.trim();
|
|
146
|
+
if (!normalized) return null;
|
|
147
|
+
const parsed = Date.parse(normalized);
|
|
148
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolveBridgeDeliveryTimestampMs({ delivery = {}, metadata = {} } = {}) {
|
|
152
|
+
return parseBridgeTimestampMs(delivery?.createdAt)
|
|
153
|
+
|| parseBridgeTimestampMs(delivery?.turnCreatedAt)
|
|
154
|
+
|| parseBridgeTimestampMs(metadata?.createdAt)
|
|
155
|
+
|| Date.now();
|
|
156
|
+
}
|
|
157
|
+
|
|
218
158
|
const CLAWORLD_RELAY_OPERATIONAL_NOTICE_PATTERNS = [
|
|
219
159
|
/^🧭\s*New session:\s+\S+/i,
|
|
220
160
|
/^🧹\s*Auto-compaction complete(?:\s*\(count \d+\))?\.$/i,
|
|
@@ -355,10 +295,11 @@ function buildClaworldDirectoryEntries(config = {}, accountId = null) {
|
|
|
355
295
|
const account = inspectClaworldChannelAccount(config, id);
|
|
356
296
|
if (!account?.enabled || !account?.configured) continue;
|
|
357
297
|
const normalizedId = String(account.accountId || id || '').trim();
|
|
358
|
-
|
|
298
|
+
const boundAgentId = normalizeClaworldText(account.relay?.agentId, null);
|
|
299
|
+
if (!normalizedId || !boundAgentId) continue;
|
|
359
300
|
if (currentAccountId && normalizedId === currentAccountId) continue;
|
|
360
301
|
entries.push({
|
|
361
|
-
id:
|
|
302
|
+
id: boundAgentId,
|
|
362
303
|
name: normalizedId,
|
|
363
304
|
handle: normalizedId,
|
|
364
305
|
rank: 100,
|
|
@@ -366,11 +307,10 @@ function buildClaworldDirectoryEntries(config = {}, accountId = null) {
|
|
|
366
307
|
}
|
|
367
308
|
|
|
368
309
|
const current = inspectClaworldChannelAccount(config, currentAccountId || null);
|
|
369
|
-
const
|
|
370
|
-
if (
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
entries.push({ id: defaultTarget, name: localPart, handle: localPart, rank: 50 });
|
|
310
|
+
const defaultTargetAgentId = normalizeClaworldText(current?.relay?.defaultTargetAgentId, null);
|
|
311
|
+
if (defaultTargetAgentId) {
|
|
312
|
+
if (!entries.some((entry) => entry.id === defaultTargetAgentId)) {
|
|
313
|
+
entries.push({ id: defaultTargetAgentId, name: defaultTargetAgentId, handle: defaultTargetAgentId, rank: 50 });
|
|
374
314
|
}
|
|
375
315
|
}
|
|
376
316
|
|
|
@@ -381,8 +321,8 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
|
|
|
381
321
|
const fromAgentId = runtimeConfig.relay?.agentId;
|
|
382
322
|
if (!fromAgentId) throw new Error('claworld relay.agentId is required for outbound send');
|
|
383
323
|
|
|
384
|
-
const
|
|
385
|
-
if (!
|
|
324
|
+
const targetAgentId = normalizeClaworldText(to, null);
|
|
325
|
+
if (!targetAgentId) throw new Error('claworld outbound targetAgentId is required');
|
|
386
326
|
|
|
387
327
|
const normalizedText = normalizeClaworldText(text, null);
|
|
388
328
|
const payload = messagePayload && typeof messagePayload === 'object'
|
|
@@ -397,6 +337,9 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
|
|
|
397
337
|
}
|
|
398
338
|
payload.source = normalizeClaworldText(payload.source, 'openclaw-claworld');
|
|
399
339
|
payload.accountId = normalizeClaworldText(payload.accountId, runtimeConfig.accountId);
|
|
340
|
+
const clientMessageId = resolveClientMessageId(
|
|
341
|
+
outboundContext.clientMessageId || outboundContext.metadata?.clientMessageId || null
|
|
342
|
+
);
|
|
400
343
|
|
|
401
344
|
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
402
345
|
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/messages`, {
|
|
@@ -408,7 +351,8 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
|
|
|
408
351
|
},
|
|
409
352
|
body: JSON.stringify({
|
|
410
353
|
fromAgentId,
|
|
411
|
-
|
|
354
|
+
targetAgentId,
|
|
355
|
+
clientMessageId,
|
|
412
356
|
payload,
|
|
413
357
|
conversation: {
|
|
414
358
|
conversationKey: outboundContext.conversationKey || outboundContext.metadata?.conversationKey || null,
|
|
@@ -433,7 +377,7 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
|
|
|
433
377
|
context: {
|
|
434
378
|
accountId: runtimeConfig.accountId || null,
|
|
435
379
|
fromAgentId,
|
|
436
|
-
|
|
380
|
+
targetAgentId,
|
|
437
381
|
status: result.status,
|
|
438
382
|
},
|
|
439
383
|
});
|
|
@@ -442,13 +386,14 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
|
|
|
442
386
|
return {
|
|
443
387
|
channel: 'claworld',
|
|
444
388
|
messageId: result.body?.turn?.turnId || `turn_${Date.now()}`,
|
|
445
|
-
chatId:
|
|
389
|
+
chatId: targetAgentId,
|
|
446
390
|
timestamp: Date.now(),
|
|
447
391
|
meta: {
|
|
392
|
+
clientMessageId,
|
|
448
393
|
sessionKey: result.body?.delivery?.sessionKey || outboundContext.sessionKey || outboundContext.SessionKey || null,
|
|
449
394
|
turnId: result.body?.turn?.turnId || null,
|
|
450
395
|
conversationKey: result.body?.conversationKey || null,
|
|
451
|
-
|
|
396
|
+
targetAgentId,
|
|
452
397
|
},
|
|
453
398
|
};
|
|
454
399
|
}
|
|
@@ -481,8 +426,7 @@ function createRelayRouteError({
|
|
|
481
426
|
context: {
|
|
482
427
|
accountId: runtimeConfig.accountId || null,
|
|
483
428
|
httpStatus: result?.status || null,
|
|
484
|
-
|
|
485
|
-
backendMessage: result?.body?.message || null,
|
|
429
|
+
...extractBackendErrorContext(result?.body),
|
|
486
430
|
...context,
|
|
487
431
|
},
|
|
488
432
|
});
|
|
@@ -491,7 +435,7 @@ function createRelayRouteError({
|
|
|
491
435
|
async function createFriendRequest({
|
|
492
436
|
runtimeConfig,
|
|
493
437
|
fromAgentId,
|
|
494
|
-
|
|
438
|
+
targetAgentId,
|
|
495
439
|
message = null,
|
|
496
440
|
metadata = {},
|
|
497
441
|
fetchImpl,
|
|
@@ -506,7 +450,7 @@ async function createFriendRequest({
|
|
|
506
450
|
},
|
|
507
451
|
body: JSON.stringify({
|
|
508
452
|
fromAgentId,
|
|
509
|
-
|
|
453
|
+
targetAgentId,
|
|
510
454
|
message: normalizeClaworldText(message, null),
|
|
511
455
|
metadata: metadata && typeof metadata === 'object' && !Array.isArray(metadata) ? metadata : {},
|
|
512
456
|
}),
|
|
@@ -517,7 +461,7 @@ async function createFriendRequest({
|
|
|
517
461
|
runtimeConfig,
|
|
518
462
|
code: 'friend_request_failed',
|
|
519
463
|
publicMessage: 'failed to create friend request',
|
|
520
|
-
context: { fromAgentId,
|
|
464
|
+
context: { fromAgentId, targetAgentId },
|
|
521
465
|
});
|
|
522
466
|
}
|
|
523
467
|
return result.body || {};
|
|
@@ -617,6 +561,7 @@ async function createChatRequest({
|
|
|
617
561
|
targetAgentId,
|
|
618
562
|
openingMessage = null,
|
|
619
563
|
worldId = null,
|
|
564
|
+
requestContext = null,
|
|
620
565
|
fetchImpl,
|
|
621
566
|
}) {
|
|
622
567
|
const normalizedTargetAgentId = normalizeClaworldText(targetAgentId, null);
|
|
@@ -644,6 +589,9 @@ async function createChatRequest({
|
|
|
644
589
|
targetAgentId: normalizedTargetAgentId,
|
|
645
590
|
openingMessage: normalizeClaworldText(openingMessage, null),
|
|
646
591
|
...(normalizeClaworldText(worldId, null) ? { worldId: normalizeClaworldText(worldId, null) } : {}),
|
|
592
|
+
...(requestContext && typeof requestContext === 'object' && !Array.isArray(requestContext)
|
|
593
|
+
? { requestContext }
|
|
594
|
+
: {}),
|
|
647
595
|
}),
|
|
648
596
|
});
|
|
649
597
|
if (!result.ok) {
|
|
@@ -658,7 +606,7 @@ async function createChatRequest({
|
|
|
658
606
|
return result.body || {};
|
|
659
607
|
}
|
|
660
608
|
|
|
661
|
-
async function
|
|
609
|
+
async function listChatInbox({
|
|
662
610
|
runtimeConfig,
|
|
663
611
|
agentId,
|
|
664
612
|
direction = null,
|
|
@@ -829,16 +777,6 @@ function isNonRecoverableBootstrapHoldError(error) {
|
|
|
829
777
|
}
|
|
830
778
|
|
|
831
779
|
function buildBootstrapHoldMessage(error, runtimeConfig = {}) {
|
|
832
|
-
if (error?.code === 'agent_code_conflict') {
|
|
833
|
-
const requestedAgentCode = normalizeClaworldText(
|
|
834
|
-
error?.context?.requestedAgentCode,
|
|
835
|
-
normalizeRuntimeRegistration(runtimeConfig).agentCode || null,
|
|
836
|
-
);
|
|
837
|
-
return requestedAgentCode
|
|
838
|
-
? `Claworld setup blocked: relay agent code ${requestedAgentCode} already exists. Add the bound appToken for this account or choose a different registration.agentCode.`
|
|
839
|
-
: 'Claworld setup blocked: relay agent code already exists. Add the bound appToken for this account or choose a different registration.agentCode.';
|
|
840
|
-
}
|
|
841
|
-
|
|
842
780
|
const publicMessage = normalizeClaworldText(error?.publicMessage, null);
|
|
843
781
|
const fallbackMessage = normalizeClaworldText(error?.message, 'relay binding bootstrap failed');
|
|
844
782
|
return `Claworld setup blocked: ${publicMessage || fallbackMessage}`;
|
|
@@ -966,6 +904,79 @@ async function fetchJson(fetchImpl, url, init = {}) {
|
|
|
966
904
|
}
|
|
967
905
|
}
|
|
968
906
|
|
|
907
|
+
async function fetchPublicIdentity({
|
|
908
|
+
runtimeConfig,
|
|
909
|
+
agentId = null,
|
|
910
|
+
fetchImpl,
|
|
911
|
+
}) {
|
|
912
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
913
|
+
const path = buildRelayJsonPath('/v1/profile/public-identity', {
|
|
914
|
+
agentId,
|
|
915
|
+
});
|
|
916
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}${path}`, {
|
|
917
|
+
method: 'GET',
|
|
918
|
+
headers: {
|
|
919
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
920
|
+
...buildRuntimeAuthHeaders(runtimeConfig),
|
|
921
|
+
},
|
|
922
|
+
});
|
|
923
|
+
if (!result.ok) {
|
|
924
|
+
createRelayRouteError({
|
|
925
|
+
result,
|
|
926
|
+
runtimeConfig,
|
|
927
|
+
code: 'public_identity_fetch_failed',
|
|
928
|
+
publicMessage: 'failed to read public identity status',
|
|
929
|
+
context: { agentId: normalizeClaworldText(agentId, null) },
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
return result.body || {};
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
async function updatePublicIdentity({
|
|
936
|
+
runtimeConfig,
|
|
937
|
+
agentId = null,
|
|
938
|
+
displayName = null,
|
|
939
|
+
fetchImpl,
|
|
940
|
+
}) {
|
|
941
|
+
const normalizedDisplayName = normalizeClaworldText(displayName, null);
|
|
942
|
+
if (!normalizedDisplayName) {
|
|
943
|
+
throw createRuntimeBoundaryError({
|
|
944
|
+
code: 'tool_input_invalid',
|
|
945
|
+
category: 'input',
|
|
946
|
+
status: 400,
|
|
947
|
+
message: 'claworld public identity update requires displayName',
|
|
948
|
+
publicMessage: 'claworld public identity update requires displayName',
|
|
949
|
+
recoverable: true,
|
|
950
|
+
context: { field: 'displayName' },
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
const baseUrl = normalizeRelayHttpBaseUrl(runtimeConfig.serverUrl);
|
|
954
|
+
const result = await fetchJson(fetchImpl, `${baseUrl}/v1/profile/public-identity`, {
|
|
955
|
+
method: 'PUT',
|
|
956
|
+
headers: {
|
|
957
|
+
'content-type': 'application/json',
|
|
958
|
+
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
959
|
+
...buildRuntimeAuthHeaders(runtimeConfig),
|
|
960
|
+
},
|
|
961
|
+
body: JSON.stringify({
|
|
962
|
+
...(normalizeClaworldText(agentId, null) ? { agentId: normalizeClaworldText(agentId, null) } : {}),
|
|
963
|
+
displayName: normalizedDisplayName,
|
|
964
|
+
}),
|
|
965
|
+
});
|
|
966
|
+
if (!result.ok) {
|
|
967
|
+
createRelayRouteError({
|
|
968
|
+
result,
|
|
969
|
+
runtimeConfig,
|
|
970
|
+
code: 'public_identity_update_failed',
|
|
971
|
+
publicMessage: 'failed to update public identity',
|
|
972
|
+
context: {
|
|
973
|
+
agentId: normalizeClaworldText(agentId, null),
|
|
974
|
+
},
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
return result.body || {};
|
|
978
|
+
}
|
|
979
|
+
|
|
969
980
|
async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
970
981
|
if (typeof fetchImpl !== 'function') {
|
|
971
982
|
throw new Error('fetch is unavailable for relay registration');
|
|
@@ -981,7 +992,6 @@ async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
|
981
992
|
...(runtimeConfig.apiKey ? { 'x-api-key': runtimeConfig.apiKey } : {}),
|
|
982
993
|
}),
|
|
983
994
|
body: JSON.stringify({
|
|
984
|
-
...(registration.enabled ? { agentCode: registration.agentCode } : {}),
|
|
985
995
|
...(registration.displayName ? { displayName: registration.displayName } : {}),
|
|
986
996
|
}),
|
|
987
997
|
});
|
|
@@ -1003,11 +1013,7 @@ async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1003
1013
|
: registerResult.status >= 500
|
|
1004
1014
|
? 'transport'
|
|
1005
1015
|
: 'config';
|
|
1006
|
-
const publicMessage =
|
|
1007
|
-
? 'relay agent code already exists; reuse its appToken or choose a different registration.agentCode'
|
|
1008
|
-
: errorCode === 'agent_code_mismatch'
|
|
1009
|
-
? 'configured relay agent code does not match the provided appToken'
|
|
1010
|
-
: 'relay registration failed';
|
|
1016
|
+
const publicMessage = 'relay registration failed';
|
|
1011
1017
|
|
|
1012
1018
|
throw createRuntimeBoundaryError({
|
|
1013
1019
|
code: errorCode,
|
|
@@ -1018,14 +1024,7 @@ async function registerRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1018
1024
|
recoverable: registerResult.status >= 500,
|
|
1019
1025
|
context: {
|
|
1020
1026
|
accountId: runtimeConfig.accountId || null,
|
|
1021
|
-
requestedAgentCode: normalizeClaworldText(
|
|
1022
|
-
registerResult.body?.requestedAgentCode,
|
|
1023
|
-
registration.agentCode || null,
|
|
1024
|
-
),
|
|
1025
|
-
authenticatedAgentCode: normalizeClaworldText(registerResult.body?.authenticatedAgentCode, null),
|
|
1026
|
-
authenticatedAddress: normalizeClaworldText(registerResult.body?.authenticatedAddress, null),
|
|
1027
1027
|
conflictingAgentId: normalizeClaworldText(registerResult.body?.agent?.agentId, null),
|
|
1028
|
-
conflictingAddress: normalizeClaworldText(registerResult.body?.agent?.address, null),
|
|
1029
1028
|
appTokenConfigured: Boolean(resolveRuntimeAppToken(runtimeConfig)),
|
|
1030
1029
|
},
|
|
1031
1030
|
});
|
|
@@ -1081,67 +1080,30 @@ async function resolveRelayAgentSummary({
|
|
|
1081
1080
|
fetchImpl,
|
|
1082
1081
|
logger,
|
|
1083
1082
|
agentId = null,
|
|
1084
|
-
agentCode = null,
|
|
1085
|
-
address = null,
|
|
1086
1083
|
}) {
|
|
1087
|
-
const
|
|
1088
|
-
runtimeConfig,
|
|
1089
|
-
agentId,
|
|
1090
|
-
agentCode,
|
|
1091
|
-
address,
|
|
1092
|
-
});
|
|
1084
|
+
const normalizedAgentId = normalizeClaworldText(agentId, null);
|
|
1093
1085
|
|
|
1094
1086
|
try {
|
|
1095
1087
|
const items = await fetchRelayAgents({ runtimeConfig, fetchImpl, logger });
|
|
1096
1088
|
const match = items
|
|
1097
|
-
.map((item) => buildRelayAgentSummary(item
|
|
1098
|
-
.find((item) =>
|
|
1099
|
-
if (requestedIdentity.agentId && item.agentId === requestedIdentity.agentId) return true;
|
|
1100
|
-
if (requestedIdentity.agentCode && item.agentCode === requestedIdentity.agentCode) return true;
|
|
1101
|
-
if (requestedIdentity.address && item.address === requestedIdentity.address) return true;
|
|
1102
|
-
if (requestedIdentity.relayLocalCode && item.relayLocalCode === requestedIdentity.relayLocalCode) return true;
|
|
1103
|
-
return false;
|
|
1104
|
-
}) || null;
|
|
1089
|
+
.map((item) => buildRelayAgentSummary(item))
|
|
1090
|
+
.find((item) => normalizedAgentId && item.agentId === normalizedAgentId) || null;
|
|
1105
1091
|
|
|
1106
1092
|
if (match) {
|
|
1107
1093
|
return {
|
|
1108
1094
|
...match,
|
|
1109
1095
|
resolved: true,
|
|
1110
|
-
resolutionSource:
|
|
1111
|
-
? 'agentId'
|
|
1112
|
-
: requestedIdentity.agentCode && match.agentCode === requestedIdentity.agentCode
|
|
1113
|
-
? 'agentCode'
|
|
1114
|
-
: requestedIdentity.address && match.address === requestedIdentity.address
|
|
1115
|
-
? 'address'
|
|
1116
|
-
: 'relayLocalCode',
|
|
1096
|
+
resolutionSource: 'agentId',
|
|
1117
1097
|
};
|
|
1118
1098
|
}
|
|
1119
1099
|
} catch {
|
|
1120
1100
|
// Fallback below keeps pairing/send tools usable even when lookup fails.
|
|
1121
1101
|
}
|
|
1122
1102
|
|
|
1123
|
-
const canInferFallbackAgentCode = Boolean(
|
|
1124
|
-
requestedIdentity.agentCode
|
|
1125
|
-
|| requestedIdentity.address
|
|
1126
|
-
|| requestedIdentity.relayLocalCode,
|
|
1127
|
-
);
|
|
1128
|
-
const fallbackAgentCode = requestedIdentity.agentCode
|
|
1129
|
-
|| (canInferFallbackAgentCode ? buildCanonicalRelayAgentCode(runtimeConfig.localAgent?.agentCode, runtimeConfig) : null)
|
|
1130
|
-
|| (canInferFallbackAgentCode ? buildCanonicalRelayAgentCode(runtimeConfig.accountId, runtimeConfig) : null);
|
|
1131
|
-
const parsedFallbackAgentCode = parseCanonicalRelayAgentCode(fallbackAgentCode);
|
|
1132
|
-
|
|
1133
1103
|
return {
|
|
1134
|
-
agentId:
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|| parsedFallbackAgentCode?.relayLocalCode
|
|
1138
|
-
|| normalizeRelayLocalAgentCode(runtimeConfig.localAgent?.agentCode, null)
|
|
1139
|
-
|| null,
|
|
1140
|
-
domain: requestedIdentity.domain
|
|
1141
|
-
|| parsedFallbackAgentCode?.domain
|
|
1142
|
-
|| normalizeRelayDomainName(inferRelayDomain(runtimeConfig), null),
|
|
1143
|
-
address: requestedIdentity.address || fallbackAgentCode || null,
|
|
1144
|
-
displayName: normalizeClaworldText(runtimeConfig.localAgent?.displayName, null),
|
|
1104
|
+
agentId: normalizedAgentId,
|
|
1105
|
+
displayName: normalizeClaworldText(runtimeConfig.registration?.displayName, normalizeClaworldText(runtimeConfig.localAgent?.displayName, null)),
|
|
1106
|
+
publicIdentity: null,
|
|
1145
1107
|
discoverable: null,
|
|
1146
1108
|
contactable: null,
|
|
1147
1109
|
online: null,
|
|
@@ -1154,10 +1116,6 @@ async function ensureAgentPairing({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1154
1116
|
const binding = await ensureRelayBinding({ runtimeConfig, fetchImpl, logger });
|
|
1155
1117
|
const pairedRuntimeConfig = binding.runtimeConfig;
|
|
1156
1118
|
const relayAgentId = normalizeClaworldText(pairedRuntimeConfig.relay?.agentId, null);
|
|
1157
|
-
const relayAgentCode = normalizeRelayLocalAgentCode(
|
|
1158
|
-
pairedRuntimeConfig.localAgent?.agentCode,
|
|
1159
|
-
normalizeRelayLocalAgentCode(pairedRuntimeConfig.accountId, null),
|
|
1160
|
-
);
|
|
1161
1119
|
|
|
1162
1120
|
if (!relayAgentId) {
|
|
1163
1121
|
return {
|
|
@@ -1170,7 +1128,6 @@ async function ensureAgentPairing({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1170
1128
|
fetchImpl,
|
|
1171
1129
|
logger,
|
|
1172
1130
|
agentId: relayAgentId,
|
|
1173
|
-
agentCode: relayAgentCode,
|
|
1174
1131
|
}),
|
|
1175
1132
|
};
|
|
1176
1133
|
}
|
|
@@ -1180,14 +1137,13 @@ async function ensureAgentPairing({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1180
1137
|
reason: null,
|
|
1181
1138
|
bindingSource: binding.bindingSource,
|
|
1182
1139
|
runtimeConfig: pairedRuntimeConfig,
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1140
|
+
relayAgent: await resolveRelayAgentSummary({
|
|
1141
|
+
runtimeConfig: pairedRuntimeConfig,
|
|
1142
|
+
fetchImpl,
|
|
1143
|
+
logger,
|
|
1144
|
+
agentId: relayAgentId,
|
|
1145
|
+
}),
|
|
1146
|
+
};
|
|
1191
1147
|
}
|
|
1192
1148
|
|
|
1193
1149
|
async function fetchPostSetupWorldDirectory({ cfg, accountId, runtimeConfig, limit = null, sort = null, page = null, fetchImpl, logger }) {
|
|
@@ -1244,7 +1200,7 @@ async function ensureRelayBinding({ runtimeConfig, fetchImpl, logger }) {
|
|
|
1244
1200
|
serverUrl: normalizedRuntimeConfig.serverUrl,
|
|
1245
1201
|
appTokenConfigured: Boolean(appToken),
|
|
1246
1202
|
registrationEnabled: registration.enabled,
|
|
1247
|
-
|
|
1203
|
+
displayName: registration.displayName || null,
|
|
1248
1204
|
hasRelayAgentId: Boolean(normalizedRuntimeConfig.relay?.agentId),
|
|
1249
1205
|
});
|
|
1250
1206
|
|
|
@@ -1269,10 +1225,12 @@ function buildDeliveryInboundEnvelope({
|
|
|
1269
1225
|
incomingText,
|
|
1270
1226
|
contextText = null,
|
|
1271
1227
|
commandText = null,
|
|
1228
|
+
timestamp = null,
|
|
1272
1229
|
deliveryId,
|
|
1273
1230
|
sessionKey,
|
|
1274
1231
|
worldId = null,
|
|
1275
1232
|
conversationKey = null,
|
|
1233
|
+
untrustedContext = [],
|
|
1276
1234
|
}) {
|
|
1277
1235
|
const envelopeOptions = runtime?.channel?.reply?.resolveEnvelopeFormatOptions
|
|
1278
1236
|
? runtime.channel.reply.resolveEnvelopeFormatOptions(currentCfg)
|
|
@@ -1282,37 +1240,43 @@ function buildDeliveryInboundEnvelope({
|
|
|
1282
1240
|
String(incomingText || '').trim(),
|
|
1283
1241
|
].filter(Boolean).join('\n\n');
|
|
1284
1242
|
const remoteLabel = String(remoteIdentity || 'unknown-peer').trim() || 'unknown-peer';
|
|
1285
|
-
const
|
|
1243
|
+
const rawBody = String(incomingText || '').trim();
|
|
1244
|
+
const normalizedCommandText = String(commandText || '').trim();
|
|
1245
|
+
const commandBody = normalizedCommandText || rawBody;
|
|
1246
|
+
const bodyForAgent = bodyText || rawBody;
|
|
1247
|
+
const contextLines = mergeUntrustedContextLines([
|
|
1286
1248
|
`[claworld peer ${remoteLabel}]`,
|
|
1287
1249
|
...(worldId ? [`[claworld world ${worldId}]`] : []),
|
|
1288
1250
|
...(conversationKey ? [`[claworld conversation ${conversationKey}]`] : []),
|
|
1289
1251
|
`[claworld session ${sessionKey}]`,
|
|
1290
1252
|
`[claworld delivery ${deliveryId}]`,
|
|
1291
|
-
];
|
|
1292
|
-
const
|
|
1293
|
-
const normalizedCommandText = String(commandText || '').trim();
|
|
1294
|
-
const commandBody = normalizedCommandText || rawBody;
|
|
1253
|
+
], untrustedContext);
|
|
1254
|
+
const envelopeTimestamp = Number.isFinite(timestamp) ? new Date(timestamp) : new Date();
|
|
1295
1255
|
|
|
1296
1256
|
if (runtime?.channel?.reply?.formatAgentEnvelope) {
|
|
1297
1257
|
return {
|
|
1298
1258
|
Body: runtime.channel.reply.formatAgentEnvelope({
|
|
1299
1259
|
channel: 'Claworld',
|
|
1300
1260
|
from: remoteLabel,
|
|
1301
|
-
timestamp:
|
|
1261
|
+
timestamp: envelopeTimestamp,
|
|
1302
1262
|
envelope: envelopeOptions,
|
|
1303
|
-
body:
|
|
1263
|
+
body: bodyForAgent,
|
|
1304
1264
|
}),
|
|
1305
1265
|
RawBody: rawBody,
|
|
1306
1266
|
CommandBody: commandBody,
|
|
1307
|
-
|
|
1267
|
+
BodyForAgent: bodyForAgent,
|
|
1268
|
+
BodyForCommands: commandBody,
|
|
1269
|
+
UntrustedContext: contextLines,
|
|
1308
1270
|
};
|
|
1309
1271
|
}
|
|
1310
1272
|
|
|
1311
1273
|
return {
|
|
1312
|
-
Body: `${remoteLabel}: ${
|
|
1274
|
+
Body: `${remoteLabel}: ${bodyForAgent}`,
|
|
1313
1275
|
RawBody: rawBody,
|
|
1314
1276
|
CommandBody: commandBody,
|
|
1315
|
-
|
|
1277
|
+
BodyForAgent: bodyForAgent,
|
|
1278
|
+
BodyForCommands: commandBody,
|
|
1279
|
+
UntrustedContext: contextLines,
|
|
1316
1280
|
};
|
|
1317
1281
|
}
|
|
1318
1282
|
|
|
@@ -1674,15 +1638,14 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1674
1638
|
: {};
|
|
1675
1639
|
const deliveryId = resolveNormalizedText(delivery.deliveryId, null);
|
|
1676
1640
|
const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
|
|
1677
|
-
const
|
|
1678
|
-
const
|
|
1641
|
+
const contextText = resolveNormalizedText(payload.contextText, null);
|
|
1642
|
+
const incomingText = resolveNormalizedText(
|
|
1643
|
+
payload.commandText,
|
|
1644
|
+
contextText ? null : resolveNormalizedText(payload.text, null),
|
|
1645
|
+
);
|
|
1646
|
+
const commandText = resolveNormalizedText(payload.commandText, incomingText);
|
|
1679
1647
|
const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
|
|
1680
|
-
const
|
|
1681
|
-
|| resolveRelayAddress(fromAgentId || '', runtimeConfig)
|
|
1682
|
-
|| fromAgentId
|
|
1683
|
-
|| 'unknown-peer';
|
|
1684
|
-
const remoteRouteIdentity = resolveRelayAddress(fromAgentId || '', runtimeConfig)
|
|
1685
|
-
|| remoteAddress;
|
|
1648
|
+
const remoteIdentity = fromAgentId || 'unknown-peer';
|
|
1686
1649
|
|
|
1687
1650
|
if (
|
|
1688
1651
|
!runtime?.channel?.reply?.finalizeInboundContext
|
|
@@ -1695,11 +1658,12 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1695
1658
|
});
|
|
1696
1659
|
return { skipped: true, reason: 'missing_runtime_bridge_hooks' };
|
|
1697
1660
|
}
|
|
1698
|
-
if (!deliveryId || !sessionKey || !incomingText) {
|
|
1661
|
+
if (!deliveryId || !sessionKey || (!incomingText && !contextText)) {
|
|
1699
1662
|
logger.warn?.(`[claworld:${runtimeAccountId}] skipping delivery bridge: missing delivery payload`, {
|
|
1700
1663
|
deliveryId,
|
|
1701
1664
|
sessionKey,
|
|
1702
1665
|
hasIncomingText: Boolean(incomingText),
|
|
1666
|
+
hasContextText: Boolean(contextText),
|
|
1703
1667
|
});
|
|
1704
1668
|
return { skipped: true, reason: 'missing_delivery_payload' };
|
|
1705
1669
|
}
|
|
@@ -1712,48 +1676,51 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1712
1676
|
const worldId = resolveDeliveryWorldId(delivery);
|
|
1713
1677
|
const commandAuthorized = shouldAuthorizeBridgedCommand({
|
|
1714
1678
|
runtimeConfig,
|
|
1715
|
-
incomingText,
|
|
1679
|
+
incomingText: commandText || incomingText,
|
|
1716
1680
|
});
|
|
1717
|
-
const
|
|
1681
|
+
const inboundTimestamp = resolveBridgeDeliveryTimestampMs({ delivery, metadata });
|
|
1682
|
+
const { Body, RawBody, CommandBody, BodyForAgent, BodyForCommands, UntrustedContext } = buildDeliveryInboundEnvelope({
|
|
1718
1683
|
runtime,
|
|
1719
1684
|
currentCfg,
|
|
1720
|
-
remoteIdentity
|
|
1685
|
+
remoteIdentity,
|
|
1721
1686
|
incomingText,
|
|
1722
1687
|
contextText,
|
|
1723
|
-
commandText
|
|
1688
|
+
commandText,
|
|
1689
|
+
timestamp: inboundTimestamp,
|
|
1724
1690
|
deliveryId,
|
|
1725
1691
|
sessionKey,
|
|
1726
1692
|
worldId,
|
|
1727
1693
|
conversationKey: metadata.conversationKey || null,
|
|
1694
|
+
untrustedContext: payload.untrustedContext,
|
|
1728
1695
|
});
|
|
1729
|
-
const
|
|
1696
|
+
const localIdentity = normalizeClaworldText(runtimeConfig.relay?.agentId, runtimeConfig.accountId);
|
|
1730
1697
|
const inboundCtx = runtime.channel.reply.finalizeInboundContext({
|
|
1731
1698
|
Body,
|
|
1732
1699
|
RawBody,
|
|
1733
1700
|
CommandBody,
|
|
1734
|
-
BodyForAgent
|
|
1735
|
-
BodyForCommands
|
|
1736
|
-
From: `claworld:${
|
|
1737
|
-
To:
|
|
1701
|
+
BodyForAgent,
|
|
1702
|
+
BodyForCommands,
|
|
1703
|
+
From: `claworld:${remoteIdentity}`,
|
|
1704
|
+
To: `claworld:${localIdentity}`,
|
|
1738
1705
|
SessionKey: sessionKey,
|
|
1739
1706
|
AccountId: runtimeConfig.accountId,
|
|
1740
1707
|
OriginatingChannel: 'claworld',
|
|
1741
|
-
OriginatingFrom:
|
|
1742
|
-
OriginatingTo:
|
|
1708
|
+
OriginatingFrom: remoteIdentity,
|
|
1709
|
+
OriginatingTo: remoteIdentity,
|
|
1743
1710
|
ChatType: 'direct',
|
|
1744
|
-
SenderName:
|
|
1745
|
-
SenderId:
|
|
1711
|
+
SenderName: remoteIdentity,
|
|
1712
|
+
SenderId: remoteIdentity,
|
|
1746
1713
|
MessageId: deliveryId,
|
|
1747
1714
|
Provider: 'claworld',
|
|
1748
1715
|
Surface: 'claworld',
|
|
1749
|
-
ConversationLabel:
|
|
1750
|
-
Timestamp:
|
|
1716
|
+
ConversationLabel: remoteIdentity,
|
|
1717
|
+
Timestamp: inboundTimestamp,
|
|
1751
1718
|
MessageSid: deliveryId,
|
|
1752
1719
|
WasMentioned: false,
|
|
1753
1720
|
CommandAuthorized: commandAuthorized,
|
|
1754
1721
|
RelayDeliveryId: deliveryId,
|
|
1755
1722
|
RelayFromAgentId: fromAgentId,
|
|
1756
|
-
UntrustedContext
|
|
1723
|
+
UntrustedContext,
|
|
1757
1724
|
});
|
|
1758
1725
|
const localAgentId = resolveBoundLocalAgentId({
|
|
1759
1726
|
cfg: currentCfg,
|
|
@@ -1784,7 +1751,7 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1784
1751
|
deliveryId,
|
|
1785
1752
|
sessionKey,
|
|
1786
1753
|
localAgentId,
|
|
1787
|
-
remoteIdentity
|
|
1754
|
+
remoteIdentity,
|
|
1788
1755
|
routeStatus: routed?.status || null,
|
|
1789
1756
|
bodyPreview: String(Body || '').slice(0, 240),
|
|
1790
1757
|
rawBodyPreview: String(RawBody || '').slice(0, 240),
|
|
@@ -1792,6 +1759,23 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1792
1759
|
commandAuthorized,
|
|
1793
1760
|
});
|
|
1794
1761
|
|
|
1762
|
+
try {
|
|
1763
|
+
if (typeof relayClient?.sendAcceptedAndWaitForAck === 'function') {
|
|
1764
|
+
await relayClient.sendAcceptedAndWaitForAck({
|
|
1765
|
+
deliveryId,
|
|
1766
|
+
sessionKey,
|
|
1767
|
+
source: 'runtime_dispatch',
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
} catch (error) {
|
|
1771
|
+
logger.warn?.(`[claworld:${runtimeAccountId}] delivery acceptance acknowledgement failed`, {
|
|
1772
|
+
deliveryId,
|
|
1773
|
+
sessionKey,
|
|
1774
|
+
localAgentId,
|
|
1775
|
+
error: error?.message || String(error),
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1795
1779
|
let {
|
|
1796
1780
|
dispatchResult,
|
|
1797
1781
|
replied,
|
|
@@ -1855,15 +1839,15 @@ async function maybeBridgeRuntimeDelivery({
|
|
|
1855
1839
|
}));
|
|
1856
1840
|
}
|
|
1857
1841
|
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1842
|
+
logger.info?.(`[claworld:${runtimeAccountId}] delivery bridge completed`, {
|
|
1843
|
+
deliveryId,
|
|
1844
|
+
sessionKey,
|
|
1845
|
+
queuedFinal: Boolean(dispatchResult?.queuedFinal),
|
|
1846
|
+
replied,
|
|
1847
|
+
keptSilent,
|
|
1848
|
+
routeStatus: routed?.status || null,
|
|
1849
|
+
runtimeOutputSummary,
|
|
1850
|
+
});
|
|
1867
1851
|
|
|
1868
1852
|
return {
|
|
1869
1853
|
skipped: false,
|
|
@@ -2345,9 +2329,9 @@ export function createClaworldChannelPlugin({
|
|
|
2345
2329
|
},
|
|
2346
2330
|
agentPrompt: {
|
|
2347
2331
|
messageToolHints: () => [
|
|
2348
|
-
'- Claworld targets are canonical
|
|
2332
|
+
'- Claworld message targets are canonical `agentId` values such as `agt_xxx`.',
|
|
2349
2333
|
'- Omit `target` to keep replying inside the current A2A session when the runtime already inferred the peer.',
|
|
2350
|
-
'-
|
|
2334
|
+
'- Resolve public identity like `displayName#code` to `agentId` before opening a new relay session to another agent.',
|
|
2351
2335
|
],
|
|
2352
2336
|
},
|
|
2353
2337
|
reload: { configPrefixes: ['channels.claworld'] },
|
|
@@ -2379,19 +2363,18 @@ export function createClaworldChannelPlugin({
|
|
|
2379
2363
|
looksLikeId: (raw, normalized) => {
|
|
2380
2364
|
const value = String(normalized || raw || '').trim();
|
|
2381
2365
|
if (!value) return false;
|
|
2382
|
-
|
|
2383
|
-
return /^[a-z0-9._:+~-]+$/i.test(value) || /^agt_[a-z0-9_-]+$/i.test(value);
|
|
2366
|
+
return /^agt_[a-z0-9_-]+$/i.test(value);
|
|
2384
2367
|
},
|
|
2385
|
-
hint: '<
|
|
2368
|
+
hint: '<agentId>',
|
|
2386
2369
|
},
|
|
2387
2370
|
},
|
|
2388
2371
|
directory: {
|
|
2389
2372
|
self: async ({ cfg, accountId } = {}) => {
|
|
2390
2373
|
const account = inspectClaworldChannelAccount(cfg || {}, accountId || null);
|
|
2391
|
-
const
|
|
2392
|
-
if (!account?.configured || !
|
|
2374
|
+
const agentId = normalizeClaworldText(account?.relay?.agentId, null);
|
|
2375
|
+
if (!account?.configured || !agentId) return null;
|
|
2393
2376
|
return {
|
|
2394
|
-
id:
|
|
2377
|
+
id: agentId,
|
|
2395
2378
|
name: account.accountId,
|
|
2396
2379
|
handle: account.accountId,
|
|
2397
2380
|
};
|
|
@@ -2474,8 +2457,6 @@ export function createClaworldChannelPlugin({
|
|
|
2474
2457
|
fetchImpl,
|
|
2475
2458
|
logger,
|
|
2476
2459
|
agentId: context.agentId || context.targetAgentId || null,
|
|
2477
|
-
agentCode: context.agentCode || context.targetAgentCode || null,
|
|
2478
|
-
address: context.address || null,
|
|
2479
2460
|
}),
|
|
2480
2461
|
},
|
|
2481
2462
|
social: {
|
|
@@ -2484,7 +2465,7 @@ export function createClaworldChannelPlugin({
|
|
|
2484
2465
|
return createFriendRequest({
|
|
2485
2466
|
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2486
2467
|
fromAgentId: resolvedContext.agentId || null,
|
|
2487
|
-
|
|
2468
|
+
targetAgentId: context.targetAgentId || null,
|
|
2488
2469
|
message: context.message || null,
|
|
2489
2470
|
metadata: context.metadata || {},
|
|
2490
2471
|
fetchImpl,
|
|
@@ -2520,18 +2501,35 @@ export function createClaworldChannelPlugin({
|
|
|
2520
2501
|
},
|
|
2521
2502
|
requestChat: async (context = {}) => {
|
|
2522
2503
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2504
|
+
const requestContext = resolvedContext.requesterSessionKey
|
|
2505
|
+
? {
|
|
2506
|
+
followUp: {
|
|
2507
|
+
sessionKey: resolvedContext.requesterSessionKey,
|
|
2508
|
+
},
|
|
2509
|
+
}
|
|
2510
|
+
: null;
|
|
2523
2511
|
return createChatRequest({
|
|
2524
2512
|
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2525
2513
|
fromAgentId: resolvedContext.agentId || null,
|
|
2526
2514
|
targetAgentId: context.targetAgentId || null,
|
|
2527
2515
|
openingMessage: context.openingMessage || context.message || context.text || null,
|
|
2528
2516
|
worldId: context.worldId || null,
|
|
2517
|
+
requestContext,
|
|
2518
|
+
fetchImpl,
|
|
2519
|
+
});
|
|
2520
|
+
},
|
|
2521
|
+
listChatInbox: async (context = {}) => {
|
|
2522
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2523
|
+
return listChatInbox({
|
|
2524
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2525
|
+
agentId: resolvedContext.agentId || null,
|
|
2526
|
+
direction: context.direction || null,
|
|
2529
2527
|
fetchImpl,
|
|
2530
2528
|
});
|
|
2531
2529
|
},
|
|
2532
2530
|
listChatRequests: async (context = {}) => {
|
|
2533
2531
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2534
|
-
return
|
|
2532
|
+
return listChatInbox({
|
|
2535
2533
|
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2536
2534
|
agentId: resolvedContext.agentId || null,
|
|
2537
2535
|
direction: context.direction || null,
|
|
@@ -2557,6 +2555,25 @@ export function createClaworldChannelPlugin({
|
|
|
2557
2555
|
});
|
|
2558
2556
|
},
|
|
2559
2557
|
},
|
|
2558
|
+
profile: {
|
|
2559
|
+
getPublicIdentity: async (context = {}) => {
|
|
2560
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2561
|
+
return fetchPublicIdentity({
|
|
2562
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2563
|
+
agentId: resolvedContext.agentId || null,
|
|
2564
|
+
fetchImpl,
|
|
2565
|
+
});
|
|
2566
|
+
},
|
|
2567
|
+
updatePublicIdentity: async (context = {}) => {
|
|
2568
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2569
|
+
return updatePublicIdentity({
|
|
2570
|
+
runtimeConfig: resolvedContext.runtimeConfig,
|
|
2571
|
+
agentId: resolvedContext.agentId || null,
|
|
2572
|
+
displayName: context.displayName || null,
|
|
2573
|
+
fetchImpl,
|
|
2574
|
+
});
|
|
2575
|
+
},
|
|
2576
|
+
},
|
|
2560
2577
|
postSetup: {
|
|
2561
2578
|
fetchWorldDirectory: async (context = {}) => {
|
|
2562
2579
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
@@ -2665,7 +2682,7 @@ export function createClaworldChannelPlugin({
|
|
|
2665
2682
|
agentId: resolvedContext.agentId || null,
|
|
2666
2683
|
displayName: context.displayName || null,
|
|
2667
2684
|
worldContextText: context.worldContextText || null,
|
|
2668
|
-
enabled: context.enabled === true,
|
|
2685
|
+
enabled: typeof context.enabled === 'boolean' ? context.enabled : true,
|
|
2669
2686
|
fetchImpl,
|
|
2670
2687
|
logger,
|
|
2671
2688
|
});
|
|
@@ -2707,6 +2724,25 @@ export function createClaworldChannelPlugin({
|
|
|
2707
2724
|
results,
|
|
2708
2725
|
demo,
|
|
2709
2726
|
productShell: {
|
|
2727
|
+
profile: {
|
|
2728
|
+
getPublicIdentity: async (context = {}) => {
|
|
2729
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2730
|
+
return fetchPublicIdentity({
|
|
2731
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
2732
|
+
agentId: resolvedContext.agentId || null,
|
|
2733
|
+
fetchImpl,
|
|
2734
|
+
});
|
|
2735
|
+
},
|
|
2736
|
+
updatePublicIdentity: async (context = {}) => {
|
|
2737
|
+
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2738
|
+
return updatePublicIdentity({
|
|
2739
|
+
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
2740
|
+
agentId: resolvedContext.agentId || null,
|
|
2741
|
+
displayName: context.displayName || null,
|
|
2742
|
+
fetchImpl,
|
|
2743
|
+
});
|
|
2744
|
+
},
|
|
2745
|
+
},
|
|
2710
2746
|
fetchWorldDirectory: async (context = {}) => {
|
|
2711
2747
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2712
2748
|
return fetchPostSetupWorldDirectory({
|
|
@@ -2847,14 +2883,14 @@ export function createClaworldChannelPlugin({
|
|
|
2847
2883
|
moderation: {
|
|
2848
2884
|
createWorld: async (context = {}) => {
|
|
2849
2885
|
const resolvedContext = await resolveBoundRuntimeContext(context);
|
|
2850
|
-
|
|
2886
|
+
return createModeratedWorld({
|
|
2851
2887
|
cfg: resolvedContext.cfg || {},
|
|
2852
2888
|
accountId: resolvedContext.accountId || null,
|
|
2853
2889
|
runtimeConfig: resolvedContext.runtimeConfig || null,
|
|
2854
2890
|
agentId: resolvedContext.agentId || null,
|
|
2855
2891
|
displayName: context.displayName || null,
|
|
2856
2892
|
worldContextText: context.worldContextText || null,
|
|
2857
|
-
enabled: context.enabled === true,
|
|
2893
|
+
enabled: typeof context.enabled === 'boolean' ? context.enabled : true,
|
|
2858
2894
|
fetchImpl,
|
|
2859
2895
|
logger,
|
|
2860
2896
|
});
|