@xfxstudio/claworld 2026.4.30-testing.2 → 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.
@@ -653,7 +653,19 @@ export function projectToolAccountViewResponse({
653
653
  identityPayload = null,
654
654
  } = {}) {
655
655
  const identityReady = identityPayload?.ready === true;
656
- const ready = pairingPayload?.status === 'paired' && identityReady;
656
+ const activationReady = pairingPayload?.status === 'paired';
657
+ const bindingReady = typeof pairingPayload?.bindingReady === 'boolean'
658
+ ? pairingPayload.bindingReady
659
+ : activationReady;
660
+ const bindingStatus = normalizeText(
661
+ pairingPayload?.bindingStatus,
662
+ activationReady
663
+ ? (bindingReady ? 'bound' : 'identity_unresolved')
664
+ : 'unactivated',
665
+ );
666
+ const ready = activationReady && identityReady;
667
+ const relayResolved = pairingPayload?.relayAgent?.resolved ?? null;
668
+ const relayOnline = pairingPayload?.relayAgent?.online ?? null;
657
669
  const resolvedShareCard = identityPayload && Object.prototype.hasOwnProperty.call(identityPayload, 'shareCard')
658
670
  ? projectToolShareCard(identityPayload.shareCard)
659
671
  : undefined;
@@ -668,7 +680,15 @@ export function projectToolAccountViewResponse({
668
680
  reason: normalizeText(pairingPayload?.reason, null),
669
681
  bindingSource: normalizeText(pairingPayload?.bindingSource, null),
670
682
  activation: {
671
- status: pairingPayload?.status === 'paired' ? 'ready' : 'pending',
683
+ status: activationReady ? 'ready' : 'pending',
684
+ },
685
+ diagnostics: {
686
+ toolReachable: true,
687
+ bindingReady,
688
+ bindingStatus,
689
+ publicIdentityReady: identityReady,
690
+ relayPresenceResolved: relayResolved,
691
+ relayOnline,
672
692
  },
673
693
  relay: {
674
694
  agentId: normalizeText(
@@ -678,9 +698,9 @@ export function projectToolAccountViewResponse({
678
698
  displayName: normalizeText(pairingPayload?.relayAgent?.displayName, null),
679
699
  discoverable: pairingPayload?.relayAgent?.discoverable ?? null,
680
700
  contactable: pairingPayload?.relayAgent?.contactable ?? null,
681
- online: pairingPayload?.relayAgent?.online ?? null,
682
- resolved: pairingPayload?.relayAgent?.resolved ?? null,
683
- bindingStatus: pairingPayload?.status === 'paired' ? 'bound' : 'unactivated',
701
+ online: relayOnline,
702
+ resolved: relayResolved,
703
+ bindingStatus,
684
704
  },
685
705
  profile: projectToolAccountProfile(identityPayload),
686
706
  ...projectToolAccountIdentityFields(identityPayload),
@@ -143,6 +143,33 @@ const CHAT_INBOX_FILTER_STATUSES = Object.freeze([
143
143
  'kickoff_failed',
144
144
  'ended',
145
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
+ ]);
146
173
 
147
174
  const TERMINAL_ACCOUNT_ACTIONS = Object.freeze([
148
175
  'view_account',
@@ -293,6 +320,117 @@ function normalizeChatInboxListFiltersInput(params = {}) {
293
320
  );
294
321
  }
295
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
+
296
434
  function parseToolResultPayload(result = null) {
297
435
  const text = result?.content?.[0]?.text;
298
436
  if (typeof text !== 'string') return null;
@@ -925,10 +1063,27 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
925
1063
  agentCode: stringParam({ description: 'Target public agent code for request.', minLength: 1 }),
926
1064
  openingMessage: stringParam({ description: 'Request/re-engagement kickoff message.', minLength: 1 }),
927
1065
  worldId: worldIdProperty,
928
- filters: objectParam({ description: 'List filters.', additionalProperties: true }),
929
- chatRequestId: stringParam({ description: 'Request id for accept/reject.', minLength: 1 }),
930
- conversationKey: stringParam({ description: 'Conversation key for get_state/close.', minLength: 1 }),
931
- localSessionKey: stringParam({ description: 'Local conversation session key for get_state/close.', minLength: 1 }),
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
+ }),
932
1087
  },
933
1088
  }),
934
1089
  async execute(toolCallId, params = {}) {
@@ -940,10 +1095,19 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
940
1095
  });
941
1096
  return rewriteToolResultName(result, manageConversationsTool, action);
942
1097
  }
943
- if (['list_related', 'get_state', 'accept', 'reject'].includes(action)) {
1098
+ if (action === 'list_related' || action === 'get_state') {
1099
+ const filters = normalizeManageConversationInboxQuery(params, action);
1100
+ const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
1101
+ ...params,
1102
+ action: 'list',
1103
+ ...(Object.keys(filters).length > 0 ? { filters } : {}),
1104
+ });
1105
+ return rewriteToolResultName(result, manageConversationsTool, action);
1106
+ }
1107
+ if (action === 'accept' || action === 'reject') {
944
1108
  const result = await requireTerminalTool(internalTools, 'claworld_chat_inbox').execute(toolCallId, {
945
1109
  ...params,
946
- action: ['list_related', 'get_state'].includes(action) ? 'list' : action,
1110
+ action,
947
1111
  });
948
1112
  return rewriteToolResultName(result, manageConversationsTool, action);
949
1113
  }
@@ -1691,45 +1855,10 @@ function buildRegisteredTools(api, plugin) {
1691
1855
  examples: ['list', 'accept', 'reject'],
1692
1856
  }),
1693
1857
  filters: objectParam({
1694
- description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
1695
- properties: {
1696
- direction: stringParam({
1697
- description: 'Filter from the current account perspective.',
1698
- enumValues: CHAT_INBOX_FILTER_DIRECTIONS,
1699
- examples: ['outbound'],
1700
- }),
1701
- mode: stringParam({
1702
- description: 'Filter to direct or world-scoped chat items.',
1703
- enumValues: CHAT_INBOX_FILTER_MODES,
1704
- examples: ['world'],
1705
- }),
1706
- status: stringParam({
1707
- description: 'Filter to pending or terminal requests, or to chats by current status.',
1708
- enumValues: CHAT_INBOX_FILTER_STATUSES,
1709
- examples: ['active'],
1710
- }),
1711
- worldId: worldIdProperty,
1712
- chatRequestId: stringParam({
1713
- description: 'Filter to one canonical chat request id.',
1714
- minLength: 1,
1715
- examples: ['req_demo_1'],
1716
- }),
1717
- conversationKey: stringParam({
1718
- description: 'Filter to one canonical conversation key.',
1719
- minLength: 1,
1720
- examples: ['pair:agt_alice::agt_moza:world:dating-demo-world'],
1721
- }),
1722
- localSessionKey: stringParam({
1723
- 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.',
1724
- minLength: 1,
1725
- examples: ['conversation:pair:agt_alice::agt_moza:world:dating-demo-world'],
1726
- }),
1727
- counterpartyAgentId: stringParam({
1728
- description: 'Filter to one counterparty agentId.',
1729
- minLength: 1,
1730
- examples: ['agt_alice'],
1731
- }),
1732
- },
1858
+ ...buildChatInboxFiltersParam({
1859
+ description: 'Optional list filters for query mode. Omit to review the full inbox across inbound and outbound items.',
1860
+ worldIdProperty,
1861
+ }),
1733
1862
  }),
1734
1863
  chatRequestId: stringParam({
1735
1864
  description: 'Canonical chat request id returned by claworld_chat_inbox pendingRequests. Required for action=accept or action=reject.',
@@ -1969,7 +2098,16 @@ function buildRegisteredTools(api, plugin) {
1969
2098
  expiresInSeconds: params.expiresInSeconds ?? null,
1970
2099
  });
1971
2100
  const pairedAgentId = identityPayload?.agentId || runtimeConfig.relay?.agentId || null;
1972
- const relayAgent = pairedAgentId
2101
+ const pairedRuntimeConfig = pairedAgentId
2102
+ ? {
2103
+ ...runtimeConfig,
2104
+ relay: {
2105
+ ...(runtimeConfig.relay && typeof runtimeConfig.relay === 'object' ? runtimeConfig.relay : {}),
2106
+ agentId: pairedAgentId,
2107
+ },
2108
+ }
2109
+ : runtimeConfig;
2110
+ const relayAgentFallback = pairedAgentId
1973
2111
  ? {
1974
2112
  agentId: pairedAgentId,
1975
2113
  displayName: normalizeText(
@@ -1990,23 +2128,39 @@ function buildRegisteredTools(api, plugin) {
1990
2128
  || runtimeConfig.relay?.appToken
1991
2129
  || runtimeConfig.relay?.credentialToken,
1992
2130
  );
2131
+ const activationReady = hasConfiguredAppToken;
2132
+ const bindingReady = activationReady && Boolean(pairedAgentId);
2133
+ const bindingStatus = activationReady
2134
+ ? (bindingReady ? 'bound' : 'identity_unresolved')
2135
+ : 'unactivated';
2136
+ let relayAgent = relayAgentFallback;
2137
+ if (hasConfiguredAppToken && pairedAgentId && typeof plugin.helpers?.pairing?.resolveAgentIdentity === 'function') {
2138
+ const resolvedRelayAgent = await plugin.helpers.pairing.resolveAgentIdentity({
2139
+ cfg,
2140
+ accountId,
2141
+ runtimeConfig: pairedRuntimeConfig,
2142
+ agentId: pairedAgentId,
2143
+ });
2144
+ if (resolvedRelayAgent && typeof resolvedRelayAgent === 'object') {
2145
+ relayAgent = {
2146
+ ...relayAgentFallback,
2147
+ ...resolvedRelayAgent,
2148
+ agentId: normalizeText(resolvedRelayAgent.agentId, pairedAgentId),
2149
+ displayName: normalizeText(resolvedRelayAgent.displayName, relayAgentFallback?.displayName ?? null),
2150
+ };
2151
+ }
2152
+ }
1993
2153
  const pairingPayload = {
1994
- status: hasConfiguredAppToken ? 'paired' : 'unpaired',
1995
- reason: hasConfiguredAppToken
2154
+ status: activationReady ? 'paired' : 'unpaired',
2155
+ bindingReady,
2156
+ bindingStatus,
2157
+ reason: activationReady
1996
2158
  ? (pairedAgentId ? null : 'missing_agent_id')
1997
2159
  : 'missing_app_token',
1998
- bindingSource: hasConfiguredAppToken
2160
+ bindingSource: activationReady
1999
2161
  ? 'configured_app_token'
2000
2162
  : (runtimeConfig.registration?.enabled === true ? 'registration_pending' : 'unbound'),
2001
- runtimeConfig: pairedAgentId
2002
- ? {
2003
- ...runtimeConfig,
2004
- relay: {
2005
- ...(runtimeConfig.relay && typeof runtimeConfig.relay === 'object' ? runtimeConfig.relay : {}),
2006
- agentId: pairedAgentId,
2007
- },
2008
- }
2009
- : runtimeConfig,
2163
+ runtimeConfig: pairedRuntimeConfig,
2010
2164
  relayAgent,
2011
2165
  };
2012
2166
  return buildToolResult(projectToolAccountViewResponse({
@@ -5,6 +5,51 @@ export const STALE_CONNECTION_CLOSE_CODE = 4002;
5
5
  export const TERMINAL_CLOSE_REASONS = new Set(['duplicate_connection_replaced', 'stale_connection']);
6
6
  export const DEFAULT_REPLY_ACK_TIMEOUT_MS = 5000;
7
7
 
8
+ function cloneObject(value, fallback = {}) {
9
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return { ...fallback };
10
+ return { ...value };
11
+ }
12
+
13
+ function normalizeEnvelopeText(value, fallback = null) {
14
+ if (value == null) return fallback;
15
+ const normalized = String(value).trim();
16
+ return normalized || fallback;
17
+ }
18
+
19
+ function resolveEnvelopeMessageId(data = {}, payload = {}) {
20
+ const notification = payload.notification && typeof payload.notification === 'object' && !Array.isArray(payload.notification)
21
+ ? payload.notification
22
+ : data.notification && typeof data.notification === 'object' && !Array.isArray(data.notification)
23
+ ? data.notification
24
+ : {};
25
+ const metadata = data.metadata && typeof data.metadata === 'object' && !Array.isArray(data.metadata)
26
+ ? data.metadata
27
+ : payload.metadata && typeof payload.metadata === 'object' && !Array.isArray(payload.metadata)
28
+ ? payload.metadata
29
+ : {};
30
+ const candidates = [
31
+ data.deliveryId,
32
+ data.inboxItemId,
33
+ data.messageId,
34
+ data.eventId,
35
+ data.notificationId,
36
+ payload.deliveryId,
37
+ payload.inboxItemId,
38
+ payload.messageId,
39
+ payload.eventId,
40
+ payload.notificationId,
41
+ metadata.messageId,
42
+ metadata.eventId,
43
+ metadata.notificationId,
44
+ notification.notificationId,
45
+ ];
46
+ for (const candidate of candidates) {
47
+ const normalized = normalizeEnvelopeText(candidate, null);
48
+ if (normalized) return normalized;
49
+ }
50
+ return null;
51
+ }
52
+
8
53
  export function normalizeRelayWebSocketUrl(serverUrl) {
9
54
  const parsed = new URL(serverUrl);
10
55
  if (parsed.protocol === 'http:') parsed.protocol = 'ws:';
@@ -23,63 +68,99 @@ export function normalizeRelayWebSocketUrl(serverUrl) {
23
68
 
24
69
  export function buildInboundEnvelope(message = {}) {
25
70
  const data = message.data || {};
71
+ const directPayload = data.payload && typeof data.payload === 'object' && !Array.isArray(data.payload)
72
+ ? { ...data.payload }
73
+ : {};
26
74
  const metadata = data.metadata && typeof data.metadata === 'object' && !Array.isArray(data.metadata)
27
75
  ? { ...data.metadata }
28
- : {};
29
- if (message.event !== 'delivery') {
30
- const eventType = normalizeOptionalText(data.eventType) || normalizeOptionalText(message.event);
31
- const notification = data.notification && typeof data.notification === 'object' && !Array.isArray(data.notification)
76
+ : directPayload.metadata && typeof directPayload.metadata === 'object' && !Array.isArray(directPayload.metadata)
77
+ ? { ...directPayload.metadata }
78
+ : cloneObject(data.meta, {});
79
+ const payloadEventType = normalizeEnvelopeText(directPayload.eventType, null);
80
+ const dataEventType = normalizeEnvelopeText(data.eventType, null);
81
+ const eventType = dataEventType
82
+ || payloadEventType
83
+ || (message.event === 'delivery' ? 'delivery' : normalizeEnvelopeText(message.event, null));
84
+ const payload = Object.keys(directPayload).length > 0
85
+ ? { ...directPayload }
86
+ : cloneObject(data, {});
87
+ if (Object.keys(directPayload).length > 0) {
88
+ for (const key of [
89
+ 'eventType',
90
+ 'eventName',
91
+ 'sessionKind',
92
+ 'sessionKey',
93
+ 'targetSessionKey',
94
+ 'targetAgentId',
95
+ 'text',
96
+ 'body',
97
+ 'notification',
98
+ 'conversationKey',
99
+ 'worldId',
100
+ ]) {
101
+ if (payload[key] == null && data[key] != null) payload[key] = data[key];
102
+ }
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)
32
107
  ? data.notification
33
108
  : {};
34
- const targetAgentId = normalizeOptionalText(
35
- data.targetAgentId
36
- || notification.targetAgentId
37
- || metadata.targetAgentId,
38
- );
39
- const sessionKey = normalizeOptionalText(
40
- data.sessionKey
41
- || notification.targetSessionKey
42
- || metadata.sessionKey,
43
- ) || (targetAgentId ? `management:${targetAgentId}` : null);
44
- if (!eventType || !sessionKey) return null;
45
- return {
46
- eventType,
47
- eventName: normalizeOptionalText(data.eventName) || normalizeOptionalText(message.event),
48
- eventId: normalizeOptionalText(data.eventId)
49
- || normalizeOptionalText(data.inboxItemId)
50
- || normalizeOptionalText(notification.notificationId)
51
- || null,
52
- sessionKey,
53
- targetAgentId,
54
- conversationKey: normalizeOptionalText(data.conversationKey)
55
- || normalizeOptionalText(notification.relatedObjects?.conversationKey)
56
- || null,
57
- worldId: normalizeOptionalText(data.worldId)
58
- || normalizeOptionalText(notification.relatedObjects?.worldId)
59
- || null,
60
- createdAt: data.createdAt || notification.createdAt || null,
61
- updatedAt: data.updatedAt || notification.updatedAt || null,
62
- payload: data && typeof data === 'object' && !Array.isArray(data)
63
- ? { ...data }
64
- : {},
65
- metadata: {
66
- ...metadata,
67
- relayEvent: normalizeOptionalText(message.event),
68
- inboxItemId: normalizeOptionalText(data.inboxItemId) || null,
69
- },
70
- };
71
- }
109
+ const targetAgentId = normalizeEnvelopeText(
110
+ data.targetAgentId,
111
+ normalizeEnvelopeText(
112
+ payload.targetAgentId,
113
+ normalizeEnvelopeText(notification.targetAgentId, normalizeEnvelopeText(metadata.targetAgentId, null)),
114
+ ),
115
+ );
116
+ const sessionKey = normalizeEnvelopeText(
117
+ data.sessionKey,
118
+ normalizeEnvelopeText(
119
+ payload.sessionKey,
120
+ normalizeEnvelopeText(
121
+ data.targetSessionKey,
122
+ normalizeEnvelopeText(
123
+ payload.targetSessionKey,
124
+ normalizeEnvelopeText(
125
+ notification.targetSessionKey,
126
+ normalizeEnvelopeText(metadata.sessionKey, targetAgentId ? `management:${targetAgentId}` : null),
127
+ ),
128
+ ),
129
+ ),
130
+ ),
131
+ );
132
+ const isDeliveryEvent = message.event === 'delivery';
133
+ const isRoutableEvent = Boolean(eventType && sessionKey);
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
+ );
72
140
  return {
73
- eventType: data.eventType || 'delivery',
74
- deliveryId: data.deliveryId || null,
75
- sessionKey: data.sessionKey || null,
76
- createdAt: data.createdAt || null,
77
- updatedAt: data.updatedAt || null,
141
+ eventType: eventType || 'delivery',
142
+ eventName,
143
+ eventId: deliveryId,
144
+ deliveryId,
145
+ sessionKey,
146
+ targetAgentId,
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,
78
157
  turnCreatedAt: data.turnCreatedAt || null,
79
- payload: data.payload && typeof data.payload === 'object' && !Array.isArray(data.payload)
80
- ? { ...data.payload }
81
- : {},
82
- metadata,
158
+ payload,
159
+ metadata: {
160
+ ...metadata,
161
+ relayEvent: normalizeEnvelopeText(message.event, null),
162
+ inboxItemId: normalizeEnvelopeText(data.inboxItemId, normalizeEnvelopeText(payload.inboxItemId, null)),
163
+ },
83
164
  };
84
165
  }
85
166