@xfxstudio/claworld 2026.4.30-testing.2 → 2026.4.30-testing.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,11 +32,6 @@ import { createInboundSessionRouter } from '../runtime/inbound-session-router.js
32
32
  import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.js';
33
33
  import { createCanonicalResultBuilder } from '../runtime/canonical-result-builder.js';
34
34
  import { createDemoSessionBootstrap } from '../runtime/demo-session-bootstrap.js';
35
- import {
36
- appendClaworldJournalEvent,
37
- buildClaworldRuntimeMaintenanceEvent,
38
- } from '../runtime/working-memory.js';
39
- import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
40
35
  import {
41
36
  broadcastModeratedWorld,
42
37
  createModeratedWorld,
@@ -137,6 +132,35 @@ function resolveNormalizedText(value, fallback = null) {
137
132
  return normalizeClaworldText(value, fallback);
138
133
  }
139
134
 
135
+ function resolveInboundMessageId({ delivery = {}, payload = {}, metadata = {} } = {}) {
136
+ const notification = payload.notification && typeof payload.notification === 'object' && !Array.isArray(payload.notification)
137
+ ? payload.notification
138
+ : delivery.notification && typeof delivery.notification === 'object' && !Array.isArray(delivery.notification)
139
+ ? delivery.notification
140
+ : {};
141
+ const candidates = [
142
+ delivery.deliveryId,
143
+ delivery.inboxItemId,
144
+ delivery.messageId,
145
+ delivery.eventId,
146
+ delivery.notificationId,
147
+ payload.deliveryId,
148
+ payload.inboxItemId,
149
+ payload.messageId,
150
+ payload.eventId,
151
+ payload.notificationId,
152
+ metadata.messageId,
153
+ metadata.eventId,
154
+ metadata.notificationId,
155
+ notification.notificationId,
156
+ ];
157
+ for (const candidate of candidates) {
158
+ const normalized = resolveNormalizedText(candidate, null);
159
+ if (normalized) return normalized;
160
+ }
161
+ return null;
162
+ }
163
+
140
164
  function isAgentScopedSessionKey(sessionKey) {
141
165
  return /^agent:[^:]+:/i.test(String(sessionKey || ''));
142
166
  }
@@ -279,6 +303,7 @@ function parseBridgeTimestampMs(value) {
279
303
 
280
304
  function resolveBridgeDeliveryTimestampMs({ delivery = {}, metadata = {} } = {}) {
281
305
  return parseBridgeTimestampMs(delivery?.createdAt)
306
+ || parseBridgeTimestampMs(delivery?.availableAt)
282
307
  || parseBridgeTimestampMs(delivery?.turnCreatedAt)
283
308
  || parseBridgeTimestampMs(metadata?.createdAt)
284
309
  || Date.now();
@@ -1757,6 +1782,7 @@ function buildDeliveryInboundEnvelope({
1757
1782
  commandText = null,
1758
1783
  timestamp = null,
1759
1784
  deliveryId,
1785
+ eventType = 'delivery',
1760
1786
  sessionKey,
1761
1787
  localSessionKey = null,
1762
1788
  worldId = null,
@@ -1775,13 +1801,16 @@ function buildDeliveryInboundEnvelope({
1775
1801
  const normalizedCommandText = String(commandText || '').trim();
1776
1802
  const commandBody = normalizedCommandText || rawBody;
1777
1803
  const bodyForAgent = bodyText || rawBody;
1804
+ const eventLabel = normalizePluginOptionalText(eventType) === 'delivery'
1805
+ ? 'delivery'
1806
+ : `event ${normalizePluginOptionalText(eventType)}`;
1778
1807
  const contextLines = mergeUntrustedContextLines([
1779
1808
  `[claworld peer ${remoteLabel}]`,
1780
1809
  ...(worldId ? [`[claworld world ${worldId}]`] : []),
1781
1810
  ...(conversationKey ? [`[claworld conversation ${conversationKey}]`] : []),
1782
1811
  ...(localSessionKey && localSessionKey !== sessionKey ? [`[claworld local session ${localSessionKey}]`] : []),
1783
1812
  `[claworld relay session ${sessionKey}]`,
1784
- `[claworld delivery ${deliveryId}]`,
1813
+ `[claworld ${eventLabel} ${deliveryId}]`,
1785
1814
  ], untrustedContext);
1786
1815
  const envelopeTimestamp = Number.isFinite(timestamp) ? new Date(timestamp) : new Date();
1787
1816
 
@@ -1812,230 +1841,6 @@ function buildDeliveryInboundEnvelope({
1812
1841
  };
1813
1842
  }
1814
1843
 
1815
- function resolveRuntimeManagementEnvelope(event = {}) {
1816
- const envelope = event?.delivery && typeof event.delivery === 'object' && !Array.isArray(event.delivery)
1817
- ? event.delivery
1818
- : {};
1819
- const payload = envelope.payload && typeof envelope.payload === 'object' && !Array.isArray(envelope.payload)
1820
- ? envelope.payload
1821
- : {};
1822
- const notification = payload.notification && typeof payload.notification === 'object' && !Array.isArray(payload.notification)
1823
- ? payload.notification
1824
- : {};
1825
- return {
1826
- envelope,
1827
- payload,
1828
- notification,
1829
- eventType: resolveNormalizedText(envelope.eventType || payload.eventType || event.eventType, null),
1830
- eventName: resolveNormalizedText(envelope.eventName || payload.eventName || notification.notificationType, null),
1831
- eventId: resolveNormalizedText(
1832
- envelope.eventId,
1833
- resolveNormalizedText(payload.inboxItemId, resolveNormalizedText(notification.notificationId, null)),
1834
- ),
1835
- sessionKey: resolveNormalizedText(envelope.sessionKey, resolveNormalizedText(payload.sessionKey, null)),
1836
- targetAgentId: resolveNormalizedText(
1837
- envelope.targetAgentId,
1838
- resolveNormalizedText(payload.targetAgentId, resolveNormalizedText(notification.targetAgentId, null)),
1839
- ),
1840
- worldId: resolveNormalizedText(envelope.worldId, resolveNormalizedText(payload.worldId, resolveNormalizedText(notification.relatedObjects?.worldId, null))),
1841
- conversationKey: resolveNormalizedText(
1842
- envelope.conversationKey,
1843
- resolveNormalizedText(payload.conversationKey, resolveNormalizedText(notification.relatedObjects?.conversationKey, null)),
1844
- ),
1845
- createdAt: envelope.createdAt || payload.createdAt || notification.createdAt || null,
1846
- };
1847
- }
1848
-
1849
- function stableJsonPreview(value = null, maxChars = 1200) {
1850
- if (!value || typeof value !== 'object') return null;
1851
- let json;
1852
- try {
1853
- json = JSON.stringify(value, null, 2);
1854
- } catch {
1855
- return null;
1856
- }
1857
- if (json.length <= maxChars) return json;
1858
- return `${json.slice(0, Math.max(0, maxChars - 3))}...`;
1859
- }
1860
-
1861
- function buildManagementRuntimeEventBody(details = {}, { localSessionKey = null } = {}) {
1862
- const notification = details.notification || {};
1863
- const relatedObjects = notification.relatedObjects || details.payload?.relatedObjects || null;
1864
- const nextActions = notification.nextActions || details.payload?.nextActions || null;
1865
- const lines = [
1866
- 'Claworld management event received.',
1867
- '',
1868
- `Event type: ${details.eventType || 'unknown'}`,
1869
- `Event name: ${details.eventName || details.eventType || 'unknown'}`,
1870
- details.eventId ? `Event id: ${details.eventId}` : null,
1871
- `Management session: ${localSessionKey || details.sessionKey || 'unknown'}`,
1872
- details.targetAgentId ? `Target agent: ${details.targetAgentId}` : null,
1873
- details.worldId ? `World: ${details.worldId}` : null,
1874
- details.conversationKey ? `Conversation: ${details.conversationKey}` : null,
1875
- '',
1876
- notification.notificationType ? `Notification type: ${notification.notificationType}` : null,
1877
- notification.title ? `Title: ${notification.title}` : null,
1878
- notification.body ? `Body: ${notification.body}` : null,
1879
- notification.whyReceived ? `Why received: ${notification.whyReceived}` : null,
1880
- relatedObjects ? 'Related objects:' : null,
1881
- relatedObjects ? stableJsonPreview(relatedObjects, 900) : null,
1882
- Array.isArray(nextActions) && nextActions.length > 0 ? 'Next actions:' : null,
1883
- Array.isArray(nextActions) && nextActions.length > 0 ? stableJsonPreview(nextActions, 900) : null,
1884
- '',
1885
- 'Handle this as a Claworld Management Session input: decide whether to record, digest, act, report, or ask the user according to the current Claworld working memory and proactivity settings.',
1886
- ].filter((line) => line != null && line !== '');
1887
- return lines.join('\n');
1888
- }
1889
-
1890
- function resolveSessionRecordArtifacts(record = null, fallbackStorePath = null) {
1891
- const normalizedRecord = record && typeof record === 'object' && !Array.isArray(record) ? record : {};
1892
- const nestedSession = normalizedRecord.session && typeof normalizedRecord.session === 'object' && !Array.isArray(normalizedRecord.session)
1893
- ? normalizedRecord.session
1894
- : {};
1895
- return {
1896
- sessionId: resolveNormalizedText(
1897
- normalizedRecord.sessionId,
1898
- resolveNormalizedText(nestedSession.sessionId, resolveNormalizedText(normalizedRecord.id, null)),
1899
- ),
1900
- sessionFile: resolveNormalizedText(
1901
- normalizedRecord.sessionFile,
1902
- resolveNormalizedText(
1903
- normalizedRecord.sessionPath,
1904
- resolveNormalizedText(
1905
- normalizedRecord.filePath,
1906
- resolveNormalizedText(normalizedRecord.path, resolveNormalizedText(nestedSession.filePath, null)),
1907
- ),
1908
- ),
1909
- ),
1910
- sessionStorePath: resolveNormalizedText(
1911
- normalizedRecord.storePath,
1912
- resolveNormalizedText(normalizedRecord.sessionStorePath, fallbackStorePath),
1913
- ),
1914
- transcriptPath: resolveNormalizedText(
1915
- normalizedRecord.transcriptPath,
1916
- resolveNormalizedText(nestedSession.transcriptPath, null),
1917
- ),
1918
- };
1919
- }
1920
-
1921
- function buildDeliveryRuntimeMaintenanceEvent({
1922
- delivery = {},
1923
- metadata = {},
1924
- payload = {},
1925
- localSessionKey = null,
1926
- localAgentId = null,
1927
- sessionArtifacts = {},
1928
- workspaceRoot = null,
1929
- } = {}) {
1930
- const deliveryId = resolveNormalizedText(delivery.deliveryId, null);
1931
- const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
1932
- const requestId = resolveNormalizedText(
1933
- metadata.kickoffRequestId,
1934
- resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
1935
- );
1936
- const worldId = resolveNormalizedText(
1937
- metadata.worldId,
1938
- resolveNormalizedText(delivery.worldId, null),
1939
- );
1940
- const conversationKey = resolveNormalizedText(metadata.conversationKey, resolveNormalizedText(delivery.conversationKey, null));
1941
- const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
1942
- const summary = [
1943
- 'Inbound Claworld delivery joined local session',
1944
- requestId ? `for request ${requestId}` : null,
1945
- fromAgentId ? `from ${fromAgentId}` : null,
1946
- ].filter(Boolean).join(' ');
1947
- return buildClaworldRuntimeMaintenanceEvent({
1948
- id: deliveryId ? `runtime:delivery:${deliveryId}` : null,
1949
- timestamp: delivery.createdAt || metadata.createdAt || payload.createdAt || null,
1950
- kind: metadata.deliveryType ? `delivery.${metadata.deliveryType}` : 'delivery',
1951
- eventType: 'delivery',
1952
- scope: 'conversation',
1953
- summary,
1954
- excerpt: payload.contextText
1955
- ? 'Inbound delivery included contextText; raw dialogue is kept in the OpenClaw session transcript.'
1956
- : 'Inbound delivery routed into an OpenClaw conversation session; raw dialogue is kept in the session transcript.',
1957
- refs: {
1958
- deliveryId,
1959
- requestId,
1960
- chatRequestId: requestId,
1961
- worldId,
1962
- conversationKey,
1963
- fromAgentId,
1964
- sessionKey: localSessionKey || sessionKey,
1965
- relaySessionKey: sessionKey,
1966
- },
1967
- relations: {
1968
- deliveryId,
1969
- requestId,
1970
- chatRequestId: requestId,
1971
- worldId,
1972
- conversationKey,
1973
- fromAgentId,
1974
- localAgentId,
1975
- localSessionKey,
1976
- relaySessionKey: sessionKey,
1977
- sessionKey: localSessionKey || sessionKey,
1978
- sessionId: sessionArtifacts.sessionId,
1979
- sessionFile: sessionArtifacts.sessionFile,
1980
- sessionStorePath: sessionArtifacts.sessionStorePath,
1981
- transcriptPath: sessionArtifacts.transcriptPath,
1982
- },
1983
- artifacts: {
1984
- workspaceRoot,
1985
- ...sessionArtifacts,
1986
- },
1987
- });
1988
- }
1989
-
1990
- function buildManagementRuntimeMaintenanceEvent(details = {}, {
1991
- localSessionKey = null,
1992
- localAgentId = null,
1993
- sessionArtifacts = {},
1994
- workspaceRoot = null,
1995
- } = {}) {
1996
- const notification = details.notification || {};
1997
- const refs = {
1998
- inboxItemId: details.payload?.inboxItemId || details.eventId,
1999
- notificationId: notification.notificationId,
2000
- notificationType: notification.notificationType || details.payload?.notificationType,
2001
- worldId: details.worldId,
2002
- conversationKey: details.conversationKey,
2003
- targetAgentId: details.targetAgentId,
2004
- sessionKey: localSessionKey || details.sessionKey,
2005
- relaySessionKey: details.sessionKey,
2006
- };
2007
- return buildClaworldRuntimeMaintenanceEvent({
2008
- id: details.eventId ? `runtime:${details.eventType}:${details.eventId}` : null,
2009
- timestamp: details.createdAt || notification.createdAt || null,
2010
- kind: details.eventName || details.eventType || 'runtime_event',
2011
- eventType: details.eventType || 'runtime_event',
2012
- scope: 'management',
2013
- summary: notification.title || notification.body || `${details.eventType || 'runtime'} event received.`,
2014
- excerpt: buildManagementRuntimeEventBody(details),
2015
- refs,
2016
- relations: {
2017
- inboxItemId: refs.inboxItemId,
2018
- notificationId: refs.notificationId,
2019
- notificationType: refs.notificationType,
2020
- worldId: details.worldId,
2021
- conversationKey: details.conversationKey,
2022
- targetAgentId: details.targetAgentId,
2023
- localAgentId,
2024
- localSessionKey,
2025
- relaySessionKey: details.sessionKey,
2026
- sessionKey: localSessionKey || details.sessionKey,
2027
- sessionId: sessionArtifacts.sessionId,
2028
- sessionFile: sessionArtifacts.sessionFile,
2029
- sessionStorePath: sessionArtifacts.sessionStorePath,
2030
- transcriptPath: sessionArtifacts.transcriptPath,
2031
- },
2032
- artifacts: {
2033
- workspaceRoot,
2034
- ...sessionArtifacts,
2035
- },
2036
- });
2037
- }
2038
-
2039
1844
  function createDeliveryReplyDispatcher({
2040
1845
  runtime,
2041
1846
  currentCfg,
@@ -2402,7 +2207,7 @@ function resolveBoundLocalAgentId({ cfg = {}, runtimeConfig = {}, relayClient }
2402
2207
  || 'main';
2403
2208
  }
2404
2209
 
2405
- async function maybeBridgeRuntimeDelivery({
2210
+ async function maybeBridgeRuntimeInboundEvent({
2406
2211
  relayClient,
2407
2212
  runtimeConfig,
2408
2213
  runtimeAccountId,
@@ -2421,36 +2226,46 @@ async function maybeBridgeRuntimeDelivery({
2421
2226
  const payload = delivery.payload && typeof delivery.payload === 'object' && !Array.isArray(delivery.payload)
2422
2227
  ? delivery.payload
2423
2228
  : {};
2424
- const deliveryId = resolveNormalizedText(delivery.deliveryId, null);
2229
+ const eventType = resolveNormalizedText(delivery.eventType, resolveNormalizedText(event?.eventType, 'delivery'));
2230
+ const deliveryId = resolveInboundMessageId({ delivery, payload, metadata });
2425
2231
  const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
2426
2232
  const contextText = resolveNormalizedText(payload.contextText, null);
2427
2233
  const incomingText = resolveNormalizedText(
2428
2234
  payload.commandText,
2429
- contextText ? null : resolveNormalizedText(payload.text, null),
2235
+ contextText ? null : resolveNormalizedText(payload.text, resolveNormalizedText(payload.body, null)),
2430
2236
  );
2431
2237
  const commandText = resolveNormalizedText(payload.commandText, incomingText);
2432
2238
  const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
2433
- const remoteIdentity = fromAgentId || 'unknown-peer';
2239
+ const routeSessionKind = resolveNormalizedText(
2240
+ event?.route?.sessionKind,
2241
+ resolveNormalizedText(delivery.sessionKind, resolveNormalizedText(payload.sessionKind, null)),
2242
+ );
2243
+ const isRelayDelivery = eventType === 'delivery';
2244
+ const allowReply = metadata.allowReply === true || (isRelayDelivery && metadata.allowReply !== false);
2245
+ const remoteIdentity = fromAgentId
2246
+ || resolveNormalizedText(metadata.source, routeSessionKind === 'management' ? 'claworld-management' : 'unknown-peer');
2434
2247
 
2435
2248
  if (
2436
2249
  !runtime?.channel?.reply?.finalizeInboundContext
2437
2250
  || !runtime?.channel?.reply?.dispatchReplyFromConfig
2438
2251
  || !runtime?.channel?.reply?.createReplyDispatcherWithTyping
2439
2252
  ) {
2440
- logger.warn?.(`[claworld:${runtimeAccountId}] skipping delivery bridge: missing runtime bridge hooks`, {
2253
+ logger.warn?.(`[claworld:${runtimeAccountId}] skipping inbound bridge: missing runtime bridge hooks`, {
2254
+ eventType,
2441
2255
  deliveryId,
2442
2256
  sessionKey,
2443
2257
  });
2444
2258
  return { skipped: true, reason: 'missing_runtime_bridge_hooks' };
2445
2259
  }
2446
2260
  if (!deliveryId || !sessionKey || (!incomingText && !contextText)) {
2447
- logger.warn?.(`[claworld:${runtimeAccountId}] skipping delivery bridge: missing delivery payload`, {
2261
+ logger.warn?.(`[claworld:${runtimeAccountId}] skipping inbound bridge: missing payload`, {
2262
+ eventType,
2448
2263
  deliveryId,
2449
2264
  sessionKey,
2450
2265
  hasIncomingText: Boolean(incomingText),
2451
2266
  hasContextText: Boolean(contextText),
2452
2267
  });
2453
- return { skipped: true, reason: 'missing_delivery_payload' };
2268
+ return { skipped: true, reason: 'missing_inbound_payload' };
2454
2269
  }
2455
2270
 
2456
2271
  const loadedCfg = await runtime.config?.loadConfig?.() || {};
@@ -2476,7 +2291,7 @@ async function maybeBridgeRuntimeDelivery({
2476
2291
  fallbackTarget: runtimeConfig.routing?.fallbackTarget,
2477
2292
  }) || null;
2478
2293
  const worldId = resolveDeliveryWorldId(delivery);
2479
- const commandAuthorized = shouldAuthorizeBridgedCommand({
2294
+ const commandAuthorized = isRelayDelivery && shouldAuthorizeBridgedCommand({
2480
2295
  runtimeConfig,
2481
2296
  incomingText: commandText || incomingText,
2482
2297
  });
@@ -2490,6 +2305,7 @@ async function maybeBridgeRuntimeDelivery({
2490
2305
  commandText,
2491
2306
  timestamp: inboundTimestamp,
2492
2307
  deliveryId,
2308
+ eventType,
2493
2309
  sessionKey,
2494
2310
  localSessionKey,
2495
2311
  worldId,
@@ -2497,6 +2313,9 @@ async function maybeBridgeRuntimeDelivery({
2497
2313
  untrustedContext: payload.untrustedContext,
2498
2314
  });
2499
2315
  const localIdentity = normalizeClaworldText(runtimeConfig.relay?.agentId, runtimeConfig.accountId);
2316
+ const isManagementSession = routeSessionKind === 'management';
2317
+ const senderName = isManagementSession ? 'Claworld' : remoteIdentity;
2318
+ const conversationLabel = isManagementSession ? 'Claworld management' : remoteIdentity;
2500
2319
  const inboundCtx = runtime.channel.reply.finalizeInboundContext({
2501
2320
  Body,
2502
2321
  RawBody,
@@ -2511,35 +2330,33 @@ async function maybeBridgeRuntimeDelivery({
2511
2330
  OriginatingChannel: 'claworld',
2512
2331
  OriginatingFrom: remoteIdentity,
2513
2332
  OriginatingTo: remoteIdentity,
2514
- ChatType: 'direct',
2515
- SenderName: remoteIdentity,
2333
+ ChatType: isManagementSession ? 'management' : 'direct',
2334
+ SenderName: senderName,
2516
2335
  SenderId: remoteIdentity,
2517
2336
  MessageId: deliveryId,
2518
2337
  Provider: 'claworld',
2519
2338
  Surface: 'claworld',
2520
- ConversationLabel: remoteIdentity,
2339
+ ConversationLabel: conversationLabel,
2521
2340
  Timestamp: inboundTimestamp,
2522
2341
  MessageSid: deliveryId,
2523
2342
  WasMentioned: false,
2524
2343
  CommandAuthorized: commandAuthorized,
2525
- RelayDeliveryId: deliveryId,
2344
+ RelayDeliveryId: isRelayDelivery ? deliveryId : null,
2526
2345
  RelayFromAgentId: fromAgentId,
2527
2346
  UntrustedContext,
2528
2347
  });
2529
2348
 
2530
- let sessionStorePath = null;
2531
- let sessionRecord = null;
2532
- let sessionArtifacts = {};
2533
2349
  if (runtime?.channel?.session?.recordInboundSession && runtime?.channel?.session?.resolveStorePath && localAgentId) {
2534
- sessionStorePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2350
+ const storePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2535
2351
  agentId: localAgentId,
2536
2352
  });
2537
- sessionRecord = await runtime.channel.session.recordInboundSession({
2538
- storePath: sessionStorePath,
2353
+ await runtime.channel.session.recordInboundSession({
2354
+ storePath,
2539
2355
  sessionKey: inboundCtx.SessionKey || sessionKey,
2540
2356
  ctx: inboundCtx,
2541
2357
  onRecordError: (error) => {
2542
2358
  logger.error?.(`[claworld:${runtimeAccountId}] failed to record inbound session`, {
2359
+ eventType,
2543
2360
  deliveryId,
2544
2361
  sessionKey,
2545
2362
  localSessionKey,
@@ -2548,81 +2365,41 @@ async function maybeBridgeRuntimeDelivery({
2548
2365
  });
2549
2366
  },
2550
2367
  });
2551
- sessionArtifacts = resolveSessionRecordArtifacts(sessionRecord, sessionStorePath);
2552
2368
  }
2553
2369
 
2554
- const workspaceRoot = resolveOpenClawWorkspaceRoot({
2555
- sources: [
2556
- { agentId: localAgentId, localAgentId },
2557
- currentCfg,
2558
- runtimeConfig,
2559
- ],
2560
- config: currentCfg,
2561
- agentId: localAgentId,
2562
- });
2563
- let journalResult = null;
2564
- if (workspaceRoot) {
2565
- try {
2566
- journalResult = await appendClaworldJournalEvent(
2567
- workspaceRoot,
2568
- buildDeliveryRuntimeMaintenanceEvent({
2569
- delivery,
2570
- metadata,
2571
- payload,
2572
- localSessionKey,
2573
- localAgentId,
2574
- sessionArtifacts,
2575
- workspaceRoot,
2576
- }),
2577
- {
2578
- trigger: 'delivery',
2579
- rule: 'runtime_delivery_joined_session',
2580
- },
2581
- );
2582
- } catch (error) {
2583
- logger.warn?.(`[claworld:${runtimeAccountId}] delivery journal append failed`, {
2584
- deliveryId,
2585
- sessionKey,
2586
- localSessionKey,
2587
- localAgentId,
2588
- error: error?.message || String(error),
2589
- });
2590
- }
2591
- }
2592
-
2593
- logger.info?.(`[claworld:${runtimeAccountId}] routing delivery into runtime session`, {
2370
+ logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'routing delivery into runtime session' : 'routing inbound event into runtime session'}`, {
2371
+ eventType,
2594
2372
  deliveryId,
2595
2373
  sessionKey,
2596
2374
  localSessionKey,
2597
2375
  localAgentId,
2598
- sessionId: sessionArtifacts.sessionId || null,
2599
- sessionFile: sessionArtifacts.sessionFile || null,
2600
2376
  remoteIdentity,
2601
2377
  routeStatus: routed?.status || null,
2602
2378
  bodyPreview: String(Body || '').slice(0, 240),
2603
2379
  rawBodyPreview: String(RawBody || '').slice(0, 240),
2604
- allowReply: metadata.allowReply !== false,
2380
+ allowReply,
2605
2381
  commandAuthorized,
2606
- journal: journalResult?.ok === true,
2607
2382
  });
2608
2383
 
2609
- try {
2610
- const acceptedResult = await relayClient.acceptDeliveryHttp({
2611
- deliveryId,
2612
- sessionKey,
2613
- source: 'runtime_dispatch',
2614
- });
2615
- if (acceptedResult.status < 200 || acceptedResult.status >= 300) {
2616
- throw new Error(`failed to submit relay delivery acceptance: ${acceptedResult.status}`);
2384
+ if (isRelayDelivery && metadata.acceptanceRequired !== false) {
2385
+ try {
2386
+ const acceptedResult = await relayClient.acceptDeliveryHttp({
2387
+ deliveryId,
2388
+ sessionKey,
2389
+ source: 'runtime_dispatch',
2390
+ });
2391
+ if (acceptedResult.status < 200 || acceptedResult.status >= 300) {
2392
+ throw new Error(`failed to submit relay delivery acceptance: ${acceptedResult.status}`);
2393
+ }
2394
+ } catch (error) {
2395
+ logger.warn?.(`[claworld:${runtimeAccountId}] delivery acceptance acknowledgement failed`, {
2396
+ deliveryId,
2397
+ sessionKey,
2398
+ localSessionKey,
2399
+ localAgentId,
2400
+ error: error?.message || String(error),
2401
+ });
2617
2402
  }
2618
- } catch (error) {
2619
- logger.warn?.(`[claworld:${runtimeAccountId}] delivery acceptance acknowledgement failed`, {
2620
- deliveryId,
2621
- sessionKey,
2622
- localSessionKey,
2623
- localAgentId,
2624
- error: error?.message || String(error),
2625
- });
2626
2403
  }
2627
2404
 
2628
2405
  let {
@@ -2637,15 +2414,16 @@ async function maybeBridgeRuntimeDelivery({
2637
2414
  deliveryId,
2638
2415
  sessionKey,
2639
2416
  localAgentId,
2640
- allowReply: metadata.allowReply !== false,
2417
+ allowReply,
2641
2418
  logger,
2642
2419
  runtimeAccountId,
2643
2420
  inboundCtx,
2644
2421
  });
2645
2422
 
2646
2423
  const shouldRetryKickoffDispatch = (
2647
- metadata.deliveryType === 'kickoff'
2648
- && metadata.allowReply !== false
2424
+ isRelayDelivery
2425
+ && metadata.deliveryType === 'kickoff'
2426
+ && allowReply
2649
2427
  && replied !== true
2650
2428
  && runtimeOutputSummary.counts.final > 0
2651
2429
  && runtimeOutputSummary.counts.nonRenderableFinal > 0
@@ -2682,14 +2460,15 @@ async function maybeBridgeRuntimeDelivery({
2682
2460
  deliveryId,
2683
2461
  sessionKey,
2684
2462
  localAgentId,
2685
- allowReply: metadata.allowReply !== false,
2463
+ allowReply,
2686
2464
  logger,
2687
2465
  runtimeAccountId,
2688
2466
  inboundCtx,
2689
2467
  }));
2690
2468
  }
2691
2469
 
2692
- logger.info?.(`[claworld:${runtimeAccountId}] delivery bridge completed`, {
2470
+ logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'delivery bridge completed' : 'inbound bridge completed'}`, {
2471
+ eventType,
2693
2472
  deliveryId,
2694
2473
  sessionKey,
2695
2474
  localSessionKey,
@@ -2712,206 +2491,6 @@ async function maybeBridgeRuntimeDelivery({
2712
2491
  };
2713
2492
  }
2714
2493
 
2715
- async function maybeBridgeRuntimeManagementEvent({
2716
- runtimeConfig,
2717
- runtimeAccountId,
2718
- event,
2719
- logger,
2720
- runtime,
2721
- cfg,
2722
- inbound,
2723
- }) {
2724
- const details = resolveRuntimeManagementEnvelope(event);
2725
- const route = event?.route || inbound?.routeInboundEvent?.(details.envelope, {
2726
- sessionTarget: runtimeConfig.routing?.sessionTarget,
2727
- fallbackTarget: runtimeConfig.routing?.fallbackTarget,
2728
- }) || null;
2729
- const sessionKey = resolveNormalizedText(details.sessionKey, resolveNormalizedText(route?.sessionKey, null));
2730
- const eventId = resolveNormalizedText(details.eventId, `${details.eventType || 'runtime_event'}:${Date.now()}`);
2731
-
2732
- if (
2733
- !runtime?.channel?.reply?.finalizeInboundContext
2734
- || !runtime?.channel?.reply?.dispatchReplyFromConfig
2735
- || !runtime?.channel?.reply?.createReplyDispatcherWithTyping
2736
- ) {
2737
- logger.warn?.(`[claworld:${runtimeAccountId}] skipping management event bridge: missing runtime bridge hooks`, {
2738
- eventType: details.eventType,
2739
- eventName: details.eventName,
2740
- sessionKey,
2741
- });
2742
- return { skipped: true, reason: 'missing_runtime_bridge_hooks' };
2743
- }
2744
- if (!details.eventType || !sessionKey || route?.status === 'invalid') {
2745
- logger.warn?.(`[claworld:${runtimeAccountId}] skipping management event bridge: missing runtime event payload`, {
2746
- eventType: details.eventType,
2747
- eventName: details.eventName,
2748
- sessionKey,
2749
- routeStatus: route?.status || null,
2750
- });
2751
- return { skipped: true, reason: 'missing_management_event_payload' };
2752
- }
2753
-
2754
- const loadedCfg = await runtime.config?.loadConfig?.() || {};
2755
- const currentCfg = {
2756
- ...(loadedCfg && typeof loadedCfg === 'object' && !Array.isArray(loadedCfg) ? loadedCfg : {}),
2757
- ...(cfg && typeof cfg === 'object' && !Array.isArray(cfg) ? cfg : {}),
2758
- agents: cfg?.agents || loadedCfg?.agents,
2759
- bindings: cfg?.bindings || loadedCfg?.bindings,
2760
- channels: cfg?.channels || loadedCfg?.channels,
2761
- session: cfg?.session || loadedCfg?.session,
2762
- };
2763
- const localAgentId = resolveBoundLocalAgentId({
2764
- cfg: currentCfg,
2765
- runtimeConfig,
2766
- });
2767
- const localSessionKey = buildAgentScopedLocalSessionKey({
2768
- sessionKey,
2769
- localAgentId,
2770
- });
2771
- const body = buildManagementRuntimeEventBody(details, { localSessionKey });
2772
- const timestamp = Date.parse(details.createdAt || '');
2773
- const inboundTimestamp = Number.isFinite(timestamp) ? timestamp : Date.now();
2774
- const localIdentity = normalizeClaworldText(runtimeConfig.relay?.agentId, runtimeConfig.accountId);
2775
- const inboundCtx = runtime.channel.reply.finalizeInboundContext({
2776
- Body: body,
2777
- RawBody: body,
2778
- CommandBody: body,
2779
- BodyForAgent: body,
2780
- BodyForCommands: body,
2781
- From: 'claworld:management',
2782
- To: `claworld:${localIdentity}`,
2783
- SessionKey: localSessionKey || sessionKey,
2784
- RelaySessionKey: sessionKey,
2785
- AccountId: runtimeConfig.accountId,
2786
- OriginatingChannel: 'claworld',
2787
- OriginatingFrom: 'management',
2788
- OriginatingTo: localIdentity,
2789
- ChatType: 'management',
2790
- SessionType: 'management',
2791
- sessionType: 'management',
2792
- sessionKind: 'management',
2793
- SenderName: 'Claworld Management',
2794
- SenderId: 'claworld-management',
2795
- MessageId: eventId,
2796
- Provider: 'claworld',
2797
- Surface: 'claworld',
2798
- ConversationLabel: 'Claworld Management',
2799
- Timestamp: inboundTimestamp,
2800
- MessageSid: eventId,
2801
- WasMentioned: false,
2802
- CommandAuthorized: false,
2803
- RelayEventId: eventId,
2804
- RelayEventType: details.eventType,
2805
- RelayEventName: details.eventName,
2806
- RelayTargetAgentId: details.targetAgentId,
2807
- });
2808
-
2809
- let sessionStorePath = null;
2810
- let sessionRecord = null;
2811
- let sessionArtifacts = {};
2812
- if (runtime?.channel?.session?.recordInboundSession && runtime?.channel?.session?.resolveStorePath && localAgentId) {
2813
- sessionStorePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2814
- agentId: localAgentId,
2815
- });
2816
- sessionRecord = await runtime.channel.session.recordInboundSession({
2817
- storePath: sessionStorePath,
2818
- sessionKey: inboundCtx.SessionKey || sessionKey,
2819
- ctx: inboundCtx,
2820
- onRecordError: (error) => {
2821
- logger.error?.(`[claworld:${runtimeAccountId}] failed to record management inbound session`, {
2822
- eventType: details.eventType,
2823
- eventName: details.eventName,
2824
- sessionKey,
2825
- localSessionKey,
2826
- localAgentId,
2827
- error: error?.message || String(error),
2828
- });
2829
- },
2830
- });
2831
- sessionArtifacts = resolveSessionRecordArtifacts(sessionRecord, sessionStorePath);
2832
- }
2833
-
2834
- const workspaceRoot = resolveOpenClawWorkspaceRoot({
2835
- sources: [
2836
- { agentId: localAgentId, localAgentId },
2837
- currentCfg,
2838
- runtimeConfig,
2839
- ],
2840
- config: currentCfg,
2841
- agentId: localAgentId,
2842
- });
2843
- let journalResult = null;
2844
- if (workspaceRoot) {
2845
- try {
2846
- journalResult = await appendClaworldJournalEvent(
2847
- workspaceRoot,
2848
- buildManagementRuntimeMaintenanceEvent(details, {
2849
- localSessionKey,
2850
- localAgentId,
2851
- sessionArtifacts,
2852
- workspaceRoot,
2853
- }),
2854
- );
2855
- } catch (error) {
2856
- logger.warn?.(`[claworld:${runtimeAccountId}] management event journal append failed`, {
2857
- eventType: details.eventType,
2858
- eventName: details.eventName,
2859
- sessionKey,
2860
- error: error?.message || String(error),
2861
- });
2862
- }
2863
- }
2864
-
2865
- logger.info?.(`[claworld:${runtimeAccountId}] routing management event into runtime session`, {
2866
- eventType: details.eventType,
2867
- eventName: details.eventName,
2868
- eventId,
2869
- sessionKey,
2870
- localSessionKey,
2871
- localAgentId,
2872
- sessionId: sessionArtifacts.sessionId || null,
2873
- sessionFile: sessionArtifacts.sessionFile || null,
2874
- routeStatus: route?.status || null,
2875
- journal: journalResult?.ok === true,
2876
- });
2877
-
2878
- const {
2879
- dispatchResult,
2880
- runtimeOutputSummary,
2881
- } = await runDeliveryReplyDispatch({
2882
- runtime,
2883
- currentCfg,
2884
- relayClient: null,
2885
- deliveryId: eventId,
2886
- sessionKey,
2887
- localAgentId,
2888
- allowReply: false,
2889
- logger,
2890
- runtimeAccountId,
2891
- inboundCtx,
2892
- });
2893
-
2894
- logger.info?.(`[claworld:${runtimeAccountId}] management event bridge completed`, {
2895
- eventType: details.eventType,
2896
- eventName: details.eventName,
2897
- eventId,
2898
- sessionKey,
2899
- localSessionKey,
2900
- queuedFinal: Boolean(dispatchResult?.queuedFinal),
2901
- routeStatus: route?.status || null,
2902
- runtimeOutputSummary,
2903
- });
2904
-
2905
- return {
2906
- skipped: false,
2907
- ok: true,
2908
- queuedFinal: Boolean(dispatchResult?.queuedFinal),
2909
- sessionKey,
2910
- localSessionKey,
2911
- routeStatus: route?.status || null,
2912
- };
2913
- }
2914
-
2915
2494
  export function createClaworldChannelPlugin({
2916
2495
  logger = console,
2917
2496
  relayClientFactory = createClaworldRelayClient,
@@ -3346,13 +2925,12 @@ export function createClaworldChannelPlugin({
3346
2925
  eventType: event?.eventType || null,
3347
2926
  target: event?.route?.target || null,
3348
2927
  deliveryId: event?.delivery?.deliveryId || null,
3349
- eventId: event?.delivery?.eventId || null,
3350
2928
  sessionKey: event?.delivery?.sessionKey || null,
3351
2929
  });
3352
2930
 
3353
- if (event?.eventType === 'delivery') {
2931
+ if (event?.delivery?.sessionKey) {
3354
2932
  const runtimeContext = accountRuntimeContexts.get(accountKey) || {};
3355
- maybeBridgeRuntimeDelivery({
2933
+ maybeBridgeRuntimeInboundEvent({
3356
2934
  relayClient,
3357
2935
  runtimeConfig,
3358
2936
  runtimeAccountId,
@@ -3362,22 +2940,7 @@ export function createClaworldChannelPlugin({
3362
2940
  cfg: runtimeContext.cfg,
3363
2941
  inbound,
3364
2942
  }).catch((error) => {
3365
- logger.error?.(`[claworld:${runtimeAccountId}] delivery bridge exception`, {
3366
- error: error?.message || String(error),
3367
- });
3368
- });
3369
- } else if (event?.route?.sessionKind === 'management' || event?.delivery?.sessionKey?.startsWith?.('management:')) {
3370
- const runtimeContext = accountRuntimeContexts.get(accountKey) || {};
3371
- maybeBridgeRuntimeManagementEvent({
3372
- runtimeConfig,
3373
- runtimeAccountId,
3374
- event,
3375
- logger,
3376
- runtime: runtimeContext.runtime,
3377
- cfg: runtimeContext.cfg,
3378
- inbound,
3379
- }).catch((error) => {
3380
- logger.error?.(`[claworld:${runtimeAccountId}] management event bridge exception`, {
2943
+ logger.error?.(`[claworld:${runtimeAccountId}] inbound bridge exception`, {
3381
2944
  error: error?.message || String(error),
3382
2945
  });
3383
2946
  });