@xfxstudio/claworld 2026.4.30-testing.3 → 2026.5.3-testing.1
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 +9 -49
- package/skills/claworld-join-and-chat/SKILL.md +1 -14
- package/src/lib/relay/agent-readable-markdown.js +1 -24
- package/src/openclaw/plugin/claworld-channel-plugin.js +677 -24
- package/src/openclaw/plugin/register.js +211 -48
- package/src/openclaw/plugin/relay-client-shared.js +41 -6
- package/src/openclaw/protocol/relay-event-protocol.js +16 -6
- package/src/openclaw/runtime/working-memory.js +926 -54
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
buildClaworldToolMaintenanceEvent,
|
|
19
19
|
ensureClaworldWorkingMemory,
|
|
20
20
|
resolveClaworldBootstrapTarget,
|
|
21
|
+
updateClaworldSessionDirectory,
|
|
21
22
|
} from '../runtime/working-memory.js';
|
|
22
23
|
import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
|
|
23
24
|
import { setClaworldRuntime } from './runtime.js';
|
|
@@ -142,6 +143,33 @@ const CHAT_INBOX_FILTER_STATUSES = Object.freeze([
|
|
|
142
143
|
'kickoff_failed',
|
|
143
144
|
'ended',
|
|
144
145
|
]);
|
|
146
|
+
const CHAT_INBOX_FILTER_KEYS = Object.freeze([
|
|
147
|
+
'direction',
|
|
148
|
+
'mode',
|
|
149
|
+
'status',
|
|
150
|
+
'worldId',
|
|
151
|
+
'chatRequestId',
|
|
152
|
+
'conversationKey',
|
|
153
|
+
'localSessionKey',
|
|
154
|
+
'counterpartyAgentId',
|
|
155
|
+
]);
|
|
156
|
+
const CHAT_INBOX_FILTER_KEY_SET = new Set(CHAT_INBOX_FILTER_KEYS);
|
|
157
|
+
const MANAGE_CONVERSATION_REQUEST_ONLY_QUERY_FIELDS = Object.freeze([
|
|
158
|
+
'displayName',
|
|
159
|
+
'agentCode',
|
|
160
|
+
'openingMessage',
|
|
161
|
+
]);
|
|
162
|
+
const MANAGE_CONVERSATION_FILTER_ONLY_TOP_LEVEL_FIELDS = Object.freeze([
|
|
163
|
+
'mode',
|
|
164
|
+
'status',
|
|
165
|
+
'worldId',
|
|
166
|
+
'counterpartyAgentId',
|
|
167
|
+
]);
|
|
168
|
+
const MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS = Object.freeze([
|
|
169
|
+
'chatRequestId',
|
|
170
|
+
'conversationKey',
|
|
171
|
+
'localSessionKey',
|
|
172
|
+
]);
|
|
145
173
|
|
|
146
174
|
const TERMINAL_ACCOUNT_ACTIONS = Object.freeze([
|
|
147
175
|
'view_account',
|
|
@@ -292,6 +320,117 @@ function normalizeChatInboxListFiltersInput(params = {}) {
|
|
|
292
320
|
);
|
|
293
321
|
}
|
|
294
322
|
|
|
323
|
+
function hasProvidedToolParam(params = {}, fieldId) {
|
|
324
|
+
if (!params || typeof params !== 'object') return false;
|
|
325
|
+
if (!Object.prototype.hasOwnProperty.call(params, fieldId)) return false;
|
|
326
|
+
const value = params[fieldId];
|
|
327
|
+
if (typeof value === 'string') return normalizeText(value, null) != null;
|
|
328
|
+
return value != null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function buildChatInboxFiltersParam({ description, worldIdProperty } = {}) {
|
|
332
|
+
return objectParam({
|
|
333
|
+
description,
|
|
334
|
+
additionalProperties: false,
|
|
335
|
+
properties: {
|
|
336
|
+
direction: stringParam({
|
|
337
|
+
description: 'Filter from the current account perspective.',
|
|
338
|
+
enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
|
|
339
|
+
examples: ['outbound'],
|
|
340
|
+
}),
|
|
341
|
+
mode: stringParam({
|
|
342
|
+
description: 'Filter to direct or world-scoped chat items.',
|
|
343
|
+
enumValues: CHAT_INBOX_FILTER_MODES,
|
|
344
|
+
examples: ['world'],
|
|
345
|
+
}),
|
|
346
|
+
status: stringParam({
|
|
347
|
+
description: 'Filter to pending or terminal requests, or to chats by current status.',
|
|
348
|
+
enumValues: CHAT_INBOX_FILTER_STATUSES,
|
|
349
|
+
examples: ['active'],
|
|
350
|
+
}),
|
|
351
|
+
worldId: worldIdProperty,
|
|
352
|
+
chatRequestId: stringParam({
|
|
353
|
+
description: 'Filter to one canonical chat request id.',
|
|
354
|
+
minLength: 1,
|
|
355
|
+
examples: ['req_demo_1'],
|
|
356
|
+
}),
|
|
357
|
+
conversationKey: stringParam({
|
|
358
|
+
description: 'Filter to one canonical conversation key.',
|
|
359
|
+
minLength: 1,
|
|
360
|
+
examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
|
|
361
|
+
}),
|
|
362
|
+
localSessionKey: stringParam({
|
|
363
|
+
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.',
|
|
364
|
+
minLength: 1,
|
|
365
|
+
examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
|
|
366
|
+
}),
|
|
367
|
+
counterpartyAgentId: stringParam({
|
|
368
|
+
description: 'Filter to one counterparty agentId.',
|
|
369
|
+
minLength: 1,
|
|
370
|
+
examples: ['agt_alice'],
|
|
371
|
+
}),
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function validateChatInboxFilterInput(filters = {}, action) {
|
|
377
|
+
const source = normalizeObject(filters, {}) || {};
|
|
378
|
+
for (const key of Object.keys(source)) {
|
|
379
|
+
if (CHAT_INBOX_FILTER_KEY_SET.has(key)) continue;
|
|
380
|
+
requireManageWorldField(`filters.${key}`, `filters.${key} is not supported for action=${action}`);
|
|
381
|
+
}
|
|
382
|
+
return source;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function normalizeManageConversationInboxQuery(params = {}, action) {
|
|
386
|
+
const normalizedAction = normalizeTerminalConversationAction(action, 'list_related');
|
|
387
|
+
const filters = validateChatInboxFilterInput(params.filters, normalizedAction);
|
|
388
|
+
|
|
389
|
+
const requestOnlyField = MANAGE_CONVERSATION_REQUEST_ONLY_QUERY_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
|
|
390
|
+
if (requestOnlyField) {
|
|
391
|
+
requireManageWorldField(requestOnlyField, `${requestOnlyField} is only supported for action=request`);
|
|
392
|
+
}
|
|
393
|
+
if (hasProvidedToolParam(params, 'limit')) {
|
|
394
|
+
requireManageWorldField('limit', `limit is not supported for action=${normalizedAction}`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const filterOnlyField = MANAGE_CONVERSATION_FILTER_ONLY_TOP_LEVEL_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
|
|
398
|
+
if (filterOnlyField) {
|
|
399
|
+
requireManageWorldField(
|
|
400
|
+
filterOnlyField,
|
|
401
|
+
`${filterOnlyField} must be passed as filters.${filterOnlyField} for action=${normalizedAction}`,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (normalizedAction !== 'get_state') {
|
|
406
|
+
const getStateOnlyField = MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS.find((fieldId) => hasProvidedToolParam(params, fieldId));
|
|
407
|
+
if (getStateOnlyField) {
|
|
408
|
+
requireManageWorldField(
|
|
409
|
+
getStateOnlyField,
|
|
410
|
+
`${getStateOnlyField} must be passed as filters.${getStateOnlyField} for action=${normalizedAction}`,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const mergedFilters = {
|
|
416
|
+
...filters,
|
|
417
|
+
...(!Object.prototype.hasOwnProperty.call(filters, 'direction') && hasProvidedToolParam(params, 'direction')
|
|
418
|
+
? { direction: params.direction }
|
|
419
|
+
: {}),
|
|
420
|
+
...(normalizedAction === 'get_state'
|
|
421
|
+
? Object.fromEntries(
|
|
422
|
+
MANAGE_CONVERSATION_GET_STATE_TARGET_FIELDS
|
|
423
|
+
.filter((fieldId) => (
|
|
424
|
+
!Object.prototype.hasOwnProperty.call(filters, fieldId)
|
|
425
|
+
&& hasProvidedToolParam(params, fieldId)
|
|
426
|
+
))
|
|
427
|
+
.map((fieldId) => [fieldId, params[fieldId]]),
|
|
428
|
+
)
|
|
429
|
+
: {}),
|
|
430
|
+
};
|
|
431
|
+
return normalizeChatInboxListFiltersInput({ filters: mergedFilters });
|
|
432
|
+
}
|
|
433
|
+
|
|
295
434
|
function parseToolResultPayload(result = null) {
|
|
296
435
|
const text = result?.content?.[0]?.text;
|
|
297
436
|
if (typeof text !== 'string') return null;
|
|
@@ -924,10 +1063,27 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
924
1063
|
agentCode: stringParam({ description: 'Target public agent code for request.', minLength: 1 }),
|
|
925
1064
|
openingMessage: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
|
|
926
1065
|
worldId: worldIdProperty,
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1066
|
+
direction: stringParam({
|
|
1067
|
+
description: 'Top-level alias for filters.direction on action=list_related/get_state.',
|
|
1068
|
+
enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
|
|
1069
|
+
examples: ['outbound'],
|
|
1070
|
+
}),
|
|
1071
|
+
filters: buildChatInboxFiltersParam({
|
|
1072
|
+
description: 'Inbox filters for action=list_related/get_state.',
|
|
1073
|
+
worldIdProperty,
|
|
1074
|
+
}),
|
|
1075
|
+
chatRequestId: stringParam({
|
|
1076
|
+
description: 'Request id for action=accept/reject, or a top-level get_state convenience target that normalizes to filters.chatRequestId.',
|
|
1077
|
+
minLength: 1,
|
|
1078
|
+
}),
|
|
1079
|
+
conversationKey: stringParam({
|
|
1080
|
+
description: 'Conversation key for action=close, or a top-level get_state convenience target that normalizes to filters.conversationKey.',
|
|
1081
|
+
minLength: 1,
|
|
1082
|
+
}),
|
|
1083
|
+
localSessionKey: stringParam({
|
|
1084
|
+
description: 'Local conversation session key for action=close, or a top-level get_state convenience target that normalizes to filters.localSessionKey.',
|
|
1085
|
+
minLength: 1,
|
|
1086
|
+
}),
|
|
931
1087
|
},
|
|
932
1088
|
}),
|
|
933
1089
|
async execute(toolCallId, params = {}) {
|
|
@@ -939,10 +1095,19 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
|
|
|
939
1095
|
});
|
|
940
1096
|
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
941
1097
|
}
|
|
942
|
-
if (
|
|
1098
|
+
if (action === 'list_related' || action === 'get_state') {
|
|
1099
|
+
const filters = normalizeManageConversationInboxQuery(params, action);
|
|
943
1100
|
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
944
1101
|
...params,
|
|
945
|
-
action:
|
|
1102
|
+
action: 'list',
|
|
1103
|
+
...(Object.keys(filters).length > 0 ? { filters } : {}),
|
|
1104
|
+
});
|
|
1105
|
+
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
1106
|
+
}
|
|
1107
|
+
if (action === 'accept' || action === 'reject') {
|
|
1108
|
+
const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
|
|
1109
|
+
...params,
|
|
1110
|
+
action,
|
|
946
1111
|
});
|
|
947
1112
|
return rewriteToolResultName(result, manageConversationsTool, action);
|
|
948
1113
|
}
|
|
@@ -1690,45 +1855,10 @@ function buildRegisteredTools(api, plugin) {
|
|
|
1690
1855
|
examples: ['list', 'accept', 'reject'],
|
|
1691
1856
|
}),
|
|
1692
1857
|
filters: objectParam({
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
|
|
1698
|
-
examples: ['outbound'],
|
|
1699
|
-
}),
|
|
1700
|
-
mode: stringParam({
|
|
1701
|
-
description: 'Filter to direct or world-scoped chat items.',
|
|
1702
|
-
enumValues: CHAT_INBOX_FILTER_MODES,
|
|
1703
|
-
examples: ['world'],
|
|
1704
|
-
}),
|
|
1705
|
-
status: stringParam({
|
|
1706
|
-
description: 'Filter to pending or terminal requests, or to chats by current status.',
|
|
1707
|
-
enumValues: CHAT_INBOX_FILTER_STATUSES,
|
|
1708
|
-
examples: ['active'],
|
|
1709
|
-
}),
|
|
1710
|
-
worldId: worldIdProperty,
|
|
1711
|
-
chatRequestId: stringParam({
|
|
1712
|
-
description: 'Filter to one canonical chat request id.',
|
|
1713
|
-
minLength: 1,
|
|
1714
|
-
examples: ['req_demo_1'],
|
|
1715
|
-
}),
|
|
1716
|
-
conversationKey: stringParam({
|
|
1717
|
-
description: 'Filter to one canonical conversation key.',
|
|
1718
|
-
minLength: 1,
|
|
1719
|
-
examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
|
|
1720
|
-
}),
|
|
1721
|
-
localSessionKey: stringParam({
|
|
1722
|
-
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.',
|
|
1723
|
-
minLength: 1,
|
|
1724
|
-
examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
|
|
1725
|
-
}),
|
|
1726
|
-
counterpartyAgentId: stringParam({
|
|
1727
|
-
description: 'Filter to one counterparty agentId.',
|
|
1728
|
-
minLength: 1,
|
|
1729
|
-
examples: ['agt_alice'],
|
|
1730
|
-
}),
|
|
1731
|
-
},
|
|
1858
|
+
...buildChatInboxFiltersParam({
|
|
1859
|
+
description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
|
|
1860
|
+
worldIdProperty,
|
|
1861
|
+
}),
|
|
1732
1862
|
}),
|
|
1733
1863
|
chatRequestId: stringParam({
|
|
1734
1864
|
description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests. Required for action=accept or action=reject.',
|
|
@@ -2095,13 +2225,45 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2095
2225
|
});
|
|
2096
2226
|
|
|
2097
2227
|
api.on('before_tool_call', async (event, ctx) => {
|
|
2098
|
-
|
|
2228
|
+
const toolName = normalizeText(event?.toolName, null);
|
|
2229
|
+
if (!toolName || !toolName.startsWith('claworld_')) return;
|
|
2099
2230
|
const params = event?.params && typeof event.params === 'object' && !Array.isArray(event.params)
|
|
2100
2231
|
? event.params
|
|
2101
2232
|
: {};
|
|
2102
|
-
if (normalizeTerminalConversationAction(params.action, null) !== 'request') return;
|
|
2103
2233
|
const requesterSessionKey = normalizeText(ctx?.sessionKey, null);
|
|
2104
|
-
if (
|
|
2234
|
+
if (requesterSessionKey) {
|
|
2235
|
+
const logger = getHookLogger(api);
|
|
2236
|
+
try {
|
|
2237
|
+
const workspaceRoot = await resolveHookWorkspaceRoot(api, event, ctx);
|
|
2238
|
+
if (workspaceRoot) {
|
|
2239
|
+
await updateClaworldSessionDirectory(
|
|
2240
|
+
workspaceRoot,
|
|
2241
|
+
{
|
|
2242
|
+
timestamp: event?.timestamp || ctx?.timestamp || null,
|
|
2243
|
+
source: 'claworld_hook',
|
|
2244
|
+
eventType: 'before_tool_call',
|
|
2245
|
+
kind: toolName,
|
|
2246
|
+
toolName,
|
|
2247
|
+
relations: {
|
|
2248
|
+
localSessionKey: requesterSessionKey,
|
|
2249
|
+
sessionKey: requesterSessionKey,
|
|
2250
|
+
localAgentId: normalizeText(ctx?.agentId ?? ctx?.AgentId, null),
|
|
2251
|
+
},
|
|
2252
|
+
context: ctx || {},
|
|
2253
|
+
},
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
} catch (error) {
|
|
2257
|
+
logger?.warn?.('[claworld:working-memory] unable to update session directory before tool call', error);
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
if (
|
|
2261
|
+
toolName !== 'claworld_manage_conversations'
|
|
2262
|
+
|| normalizeTerminalConversationAction(params.action, null) !== 'request'
|
|
2263
|
+
|| !requesterSessionKey
|
|
2264
|
+
) {
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2105
2267
|
return {
|
|
2106
2268
|
params: {
|
|
2107
2269
|
...params,
|
|
@@ -2123,6 +2285,7 @@ export function registerClaworldPluginFull(api, plugin) {
|
|
|
2123
2285
|
params: event?.params || {},
|
|
2124
2286
|
result: hookToolResult(event),
|
|
2125
2287
|
timestamp: event?.timestamp || ctx?.timestamp || null,
|
|
2288
|
+
context: ctx || {},
|
|
2126
2289
|
});
|
|
2127
2290
|
if (!maintenanceEvent) return;
|
|
2128
2291
|
await appendClaworldJournalEvent(workspaceRoot, maintenanceEvent);
|
|
@@ -95,13 +95,23 @@ export function buildInboundEnvelope(message = {}) {
|
|
|
95
95
|
'text',
|
|
96
96
|
'body',
|
|
97
97
|
'notification',
|
|
98
|
+
'conversationKey',
|
|
99
|
+
'worldId',
|
|
98
100
|
]) {
|
|
99
101
|
if (payload[key] == null && data[key] != null) payload[key] = data[key];
|
|
100
102
|
}
|
|
101
103
|
}
|
|
104
|
+
const notification = payload.notification && typeof payload.notification === 'object' && !Array.isArray(payload.notification)
|
|
105
|
+
? payload.notification
|
|
106
|
+
: data.notification && typeof data.notification === 'object' && !Array.isArray(data.notification)
|
|
107
|
+
? data.notification
|
|
108
|
+
: {};
|
|
102
109
|
const targetAgentId = normalizeEnvelopeText(
|
|
103
110
|
data.targetAgentId,
|
|
104
|
-
normalizeEnvelopeText(
|
|
111
|
+
normalizeEnvelopeText(
|
|
112
|
+
payload.targetAgentId,
|
|
113
|
+
normalizeEnvelopeText(notification.targetAgentId, normalizeEnvelopeText(metadata.targetAgentId, null)),
|
|
114
|
+
),
|
|
105
115
|
);
|
|
106
116
|
const sessionKey = normalizeEnvelopeText(
|
|
107
117
|
data.sessionKey,
|
|
@@ -109,23 +119,48 @@ export function buildInboundEnvelope(message = {}) {
|
|
|
109
119
|
payload.sessionKey,
|
|
110
120
|
normalizeEnvelopeText(
|
|
111
121
|
data.targetSessionKey,
|
|
112
|
-
normalizeEnvelopeText(
|
|
122
|
+
normalizeEnvelopeText(
|
|
123
|
+
payload.targetSessionKey,
|
|
124
|
+
normalizeEnvelopeText(
|
|
125
|
+
notification.targetSessionKey,
|
|
126
|
+
normalizeEnvelopeText(metadata.sessionKey, targetAgentId ? `management:${targetAgentId}` : null),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
113
129
|
),
|
|
114
130
|
),
|
|
115
131
|
);
|
|
116
132
|
const isDeliveryEvent = message.event === 'delivery';
|
|
117
133
|
const isRoutableEvent = Boolean(eventType && sessionKey);
|
|
118
134
|
if (!isDeliveryEvent && !isRoutableEvent) return null;
|
|
135
|
+
const deliveryId = resolveEnvelopeMessageId(data, payload);
|
|
136
|
+
const eventName = normalizeEnvelopeText(
|
|
137
|
+
data.eventName,
|
|
138
|
+
normalizeEnvelopeText(payload.eventName, isDeliveryEvent ? null : normalizeEnvelopeText(message.event, null)),
|
|
139
|
+
);
|
|
119
140
|
return {
|
|
120
141
|
eventType: eventType || 'delivery',
|
|
121
|
-
|
|
142
|
+
eventName,
|
|
143
|
+
eventId: deliveryId,
|
|
144
|
+
deliveryId,
|
|
122
145
|
sessionKey,
|
|
123
146
|
targetAgentId,
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
conversationKey: normalizeEnvelopeText(
|
|
148
|
+
data.conversationKey,
|
|
149
|
+
normalizeEnvelopeText(payload.conversationKey, normalizeEnvelopeText(notification.relatedObjects?.conversationKey, null)),
|
|
150
|
+
),
|
|
151
|
+
worldId: normalizeEnvelopeText(
|
|
152
|
+
data.worldId,
|
|
153
|
+
normalizeEnvelopeText(payload.worldId, normalizeEnvelopeText(notification.relatedObjects?.worldId, null)),
|
|
154
|
+
),
|
|
155
|
+
createdAt: data.createdAt || payload.createdAt || data.availableAt || payload.availableAt || notification.createdAt || null,
|
|
156
|
+
updatedAt: data.updatedAt || payload.updatedAt || notification.updatedAt || null,
|
|
126
157
|
turnCreatedAt: data.turnCreatedAt || null,
|
|
127
158
|
payload,
|
|
128
|
-
metadata
|
|
159
|
+
metadata: {
|
|
160
|
+
...metadata,
|
|
161
|
+
relayEvent: normalizeEnvelopeText(message.event, null),
|
|
162
|
+
inboxItemId: normalizeEnvelopeText(data.inboxItemId, normalizeEnvelopeText(payload.inboxItemId, null)),
|
|
163
|
+
},
|
|
129
164
|
};
|
|
130
165
|
}
|
|
131
166
|
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export const CLAWORLD_PLUGIN_BRIDGE_PROTOCOL = 'claworld.delivery_reply.v1';
|
|
2
2
|
|
|
3
3
|
const DELIVERY_EVENT_TYPE = 'delivery';
|
|
4
|
+
const MANAGEMENT_EVENT_TYPES = new Set([
|
|
5
|
+
'notification',
|
|
6
|
+
'domain_notification',
|
|
7
|
+
'management_wake',
|
|
8
|
+
'management_tick',
|
|
9
|
+
'conversation_lifecycle',
|
|
10
|
+
'platform_recommendation',
|
|
11
|
+
'ops_recommendation',
|
|
12
|
+
]);
|
|
4
13
|
|
|
5
14
|
function normalizeText(value, fallback = null) {
|
|
6
15
|
if (value == null) return fallback;
|
|
@@ -16,27 +25,28 @@ function normalizePayload(payload = null) {
|
|
|
16
25
|
export function createRelayEventProtocol() {
|
|
17
26
|
return {
|
|
18
27
|
version: CLAWORLD_PLUGIN_BRIDGE_PROTOCOL,
|
|
19
|
-
eventTypes: [DELIVERY_EVENT_TYPE],
|
|
20
|
-
requiredEnvelopeFields: ['eventType', '
|
|
28
|
+
eventTypes: [DELIVERY_EVENT_TYPE, ...MANAGEMENT_EVENT_TYPES],
|
|
29
|
+
requiredEnvelopeFields: ['eventType', 'sessionKey', 'payload'],
|
|
21
30
|
describeEvent(event = {}) {
|
|
22
31
|
const payload = normalizePayload(event.payload);
|
|
23
32
|
const missing = [];
|
|
24
|
-
|
|
33
|
+
const eventType = normalizeText(event.eventType, null);
|
|
34
|
+
if (eventType !== DELIVERY_EVENT_TYPE && !MANAGEMENT_EVENT_TYPES.has(eventType)) {
|
|
25
35
|
missing.push('eventType');
|
|
26
36
|
}
|
|
27
|
-
if (!normalizeText(event.deliveryId, null)) {
|
|
37
|
+
if (eventType === DELIVERY_EVENT_TYPE && !normalizeText(event.deliveryId, null)) {
|
|
28
38
|
missing.push('deliveryId');
|
|
29
39
|
}
|
|
30
40
|
if (!normalizeText(event.sessionKey, null)) {
|
|
31
41
|
missing.push('sessionKey');
|
|
32
42
|
}
|
|
33
|
-
if (!normalizeText(payload.text, null)) {
|
|
43
|
+
if (eventType === DELIVERY_EVENT_TYPE && !normalizeText(payload.text, null)) {
|
|
34
44
|
missing.push('payload.text');
|
|
35
45
|
}
|
|
36
46
|
return {
|
|
37
47
|
ok: missing.length === 0,
|
|
38
48
|
missing,
|
|
39
|
-
role: 'delivery',
|
|
49
|
+
role: eventType === DELIVERY_EVENT_TYPE ? 'delivery' : 'management',
|
|
40
50
|
};
|
|
41
51
|
},
|
|
42
52
|
};
|