@xfxstudio/claworld 2026.4.30-runtime-binding-fix.3 → 2026.4.30-testing.2

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,6 +32,11 @@ 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';
35
40
  import {
36
41
  broadcastModeratedWorld,
37
42
  createModeratedWorld,
@@ -1807,6 +1812,230 @@ function buildDeliveryInboundEnvelope({
1807
1812
  };
1808
1813
  }
1809
1814
 
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
+
1810
2039
  function createDeliveryReplyDispatcher({
1811
2040
  runtime,
1812
2041
  currentCfg,
@@ -2298,12 +2527,15 @@ async function maybeBridgeRuntimeDelivery({
2298
2527
  UntrustedContext,
2299
2528
  });
2300
2529
 
2530
+ let sessionStorePath = null;
2531
+ let sessionRecord = null;
2532
+ let sessionArtifacts = {};
2301
2533
  if (runtime?.channel?.session?.recordInboundSession && runtime?.channel?.session?.resolveStorePath && localAgentId) {
2302
- const storePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2534
+ sessionStorePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2303
2535
  agentId: localAgentId,
2304
2536
  });
2305
- await runtime.channel.session.recordInboundSession({
2306
- storePath,
2537
+ sessionRecord = await runtime.channel.session.recordInboundSession({
2538
+ storePath: sessionStorePath,
2307
2539
  sessionKey: inboundCtx.SessionKey || sessionKey,
2308
2540
  ctx: inboundCtx,
2309
2541
  onRecordError: (error) => {
@@ -2316,6 +2548,46 @@ async function maybeBridgeRuntimeDelivery({
2316
2548
  });
2317
2549
  },
2318
2550
  });
2551
+ sessionArtifacts = resolveSessionRecordArtifacts(sessionRecord, sessionStorePath);
2552
+ }
2553
+
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
+ }
2319
2591
  }
2320
2592
 
2321
2593
  logger.info?.(`[claworld:${runtimeAccountId}] routing delivery into runtime session`, {
@@ -2323,12 +2595,15 @@ async function maybeBridgeRuntimeDelivery({
2323
2595
  sessionKey,
2324
2596
  localSessionKey,
2325
2597
  localAgentId,
2598
+ sessionId: sessionArtifacts.sessionId || null,
2599
+ sessionFile: sessionArtifacts.sessionFile || null,
2326
2600
  remoteIdentity,
2327
2601
  routeStatus: routed?.status || null,
2328
2602
  bodyPreview: String(Body || '').slice(0, 240),
2329
2603
  rawBodyPreview: String(RawBody || '').slice(0, 240),
2330
2604
  allowReply: metadata.allowReply !== false,
2331
2605
  commandAuthorized,
2606
+ journal: journalResult?.ok === true,
2332
2607
  });
2333
2608
 
2334
2609
  try {
@@ -2437,6 +2712,206 @@ async function maybeBridgeRuntimeDelivery({
2437
2712
  };
2438
2713
  }
2439
2714
 
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
+
2440
2915
  export function createClaworldChannelPlugin({
2441
2916
  logger = console,
2442
2917
  relayClientFactory = createClaworldRelayClient,
@@ -2479,75 +2954,6 @@ export function createClaworldChannelPlugin({
2479
2954
  });
2480
2955
  }
2481
2956
 
2482
- function resolveCachedAccountBinding({ runtimeConfig, accountId = null }) {
2483
- const normalizedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
2484
- const accountKey = resolveAccountBindingKey(normalizedRuntimeConfig, accountId || null);
2485
- const cachedBinding = accountBindingStates.get(accountKey)?.binding || null;
2486
- if (
2487
- !cachedBinding
2488
- || !cachedBinding.runtimeConfig?.serverUrl
2489
- || cachedBinding.runtimeConfig.serverUrl !== normalizedRuntimeConfig.serverUrl
2490
- ) {
2491
- return null;
2492
- }
2493
-
2494
- return {
2495
- ...cachedBinding,
2496
- runtimeConfig: mergeBoundRuntimeConfig(normalizedRuntimeConfig, cachedBinding.runtimeConfig),
2497
- bindingSource: cachedBinding.bindingSource || 'binding_cache',
2498
- };
2499
- }
2500
-
2501
- function commitRuntimeBinding({
2502
- context = {},
2503
- runtime = null,
2504
- runtimeSource = null,
2505
- accountId = null,
2506
- runtimeConfig = {},
2507
- bindingSource = 'configured_app_token',
2508
- relayAgent = null,
2509
- } = {}) {
2510
- const normalizedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
2511
- const normalizedAccountId = normalizeClaworldText(
2512
- normalizedRuntimeConfig.accountId,
2513
- normalizeClaworldText(accountId, normalizeClaworldText(context.accountId, 'default')),
2514
- );
2515
- const accountKey = resolveAccountBindingKey(normalizedRuntimeConfig, normalizedAccountId);
2516
- const runtimeResolution = runtimeSource
2517
- ? { runtime, runtimeSource }
2518
- : resolvePluginRuntimeCandidate(runtime || context.runtime || null);
2519
- const currentRuntimeContext = accountRuntimeContexts.get(accountKey)
2520
- || accountRuntimeContexts.get(normalizedAccountId)
2521
- || null;
2522
-
2523
- rememberAccountBinding({
2524
- runtimeConfig: normalizedRuntimeConfig,
2525
- accountId: normalizedAccountId,
2526
- bindingSource,
2527
- relayAgent,
2528
- });
2529
-
2530
- accountRuntimeContexts.set(accountKey, {
2531
- ...(currentRuntimeContext || {}),
2532
- runtime: currentRuntimeContext?.runtime || runtimeResolution.runtime || null,
2533
- runtimeSource: currentRuntimeContext?.runtimeSource || runtimeResolution.runtimeSource || null,
2534
- cfg: currentRuntimeContext?.cfg || context.cfg || null,
2535
- accountId: normalizedAccountId,
2536
- runtimeConfig: normalizedRuntimeConfig,
2537
- relayAgent: relayAgent || currentRuntimeContext?.relayAgent || null,
2538
- bindingSource,
2539
- deferredFailure: null,
2540
- deferredErrorMessage: null,
2541
- });
2542
-
2543
- return {
2544
- accountKey,
2545
- accountId: normalizedAccountId,
2546
- runtimeConfig: normalizedRuntimeConfig,
2547
- bindingSource,
2548
- };
2549
- }
2550
-
2551
2957
  async function ensureAccountRelayBinding({ runtimeConfig, accountId = null }) {
2552
2958
  const normalizedRuntimeConfig = applyRuntimeIdentity(runtimeConfig);
2553
2959
  const accountKey = resolveAccountBindingKey(normalizedRuntimeConfig, accountId || null);
@@ -2562,7 +2968,9 @@ export function createClaworldChannelPlugin({
2562
2968
  return {
2563
2969
  ...cachedBinding,
2564
2970
  runtimeConfig: mergeBoundRuntimeConfig(normalizedRuntimeConfig, cachedBinding.runtimeConfig),
2565
- bindingSource: cachedBinding.bindingSource || 'binding_cache',
2971
+ bindingSource: cachedBinding.bindingSource === 'configured_app_token'
2972
+ ? 'configured_app_token'
2973
+ : 'binding_cache',
2566
2974
  };
2567
2975
  }
2568
2976
 
@@ -2683,13 +3091,8 @@ export function createClaworldChannelPlugin({
2683
3091
  };
2684
3092
  }
2685
3093
 
2686
- const backupAgentId = normalizeClaworldText(
2687
- backup?.agentId,
2688
- normalizeClaworldText(runtimeConfig?.relay?.agentId, null),
2689
- );
2690
3094
  const restoredRuntimeConfig = applyRuntimeIdentity(runtimeConfig, {
2691
3095
  appToken: backupToken,
2692
- agentId: backupAgentId,
2693
3096
  });
2694
3097
 
2695
3098
  try {
@@ -2697,7 +3100,6 @@ export function createClaworldChannelPlugin({
2697
3100
  runtime,
2698
3101
  accountId,
2699
3102
  appToken: backupToken,
2700
- relayAgentId: backupAgentId,
2701
3103
  });
2702
3104
  } catch (error) {
2703
3105
  logger.warn?.(`[claworld:${accountId || 'default'}] failed to persist restored runtime appToken`, {
@@ -2725,89 +3127,16 @@ export function createClaworldChannelPlugin({
2725
3127
  accountId: runtimeConfig.accountId || accountId || null,
2726
3128
  runtimeConfig,
2727
3129
  agentId: context.agentId || runtimeConfig.relay?.agentId || null,
2728
- bindingSource: runtimeContext?.deferredFailure
2729
- ? 'runtime_context_deferred'
2730
- : (runtimeContext?.bindingSource || 'runtime_context'),
2731
- };
2732
- }
2733
-
2734
- async function resolveAccountViewRuntimeContext(context = {}) {
2735
- const configuredContext = resolveConfiguredRuntimeContext(context);
2736
- const cfg = configuredContext.cfg || {};
2737
- const accountId = configuredContext.accountId || null;
2738
- let runtimeConfig = configuredContext.runtimeConfig;
2739
- const runtimeResolution = resolvePluginRuntimeCandidate(
2740
- context.runtime || configuredContext.runtime || null,
2741
- );
2742
- let bindingSource = configuredContext.bindingSource || null;
2743
- let relayAgent = configuredContext.relayAgent || null;
2744
-
2745
- const runtimeContext = accountRuntimeContexts.get(
2746
- resolveAccountBindingKey(runtimeConfig, accountId || null),
2747
- ) || accountRuntimeContexts.get(accountId || 'default') || null;
2748
- if (runtimeContext?.runtimeConfig && !runtimeContext?.deferredFailure) {
2749
- runtimeConfig = mergeBoundRuntimeConfig(runtimeConfig, runtimeContext.runtimeConfig);
2750
- bindingSource = runtimeContext.bindingSource || bindingSource || 'runtime_context';
2751
- relayAgent = runtimeContext.relayAgent || relayAgent;
2752
- }
2753
-
2754
- const cachedBinding = resolveCachedAccountBinding({ runtimeConfig, accountId });
2755
- if (cachedBinding && resolveRuntimeAppToken(cachedBinding.runtimeConfig)) {
2756
- runtimeConfig = cachedBinding.runtimeConfig;
2757
- bindingSource = cachedBinding.bindingSource || bindingSource || 'binding_cache';
2758
- relayAgent = cachedBinding.relayAgent || relayAgent;
2759
- }
2760
-
2761
- if (!resolveRuntimeAppToken(runtimeConfig)) {
2762
- const restoredBinding = await maybeRestoreRuntimeAppToken({
2763
- runtime: runtimeResolution.runtime,
2764
- accountId,
2765
- runtimeConfig,
2766
- });
2767
- if (restoredBinding.restored) {
2768
- runtimeConfig = restoredBinding.runtimeConfig;
2769
- bindingSource = 'installer_state_backup';
2770
- logger.info?.(`[claworld:${accountId || 'default'}] restored runtime binding from installer state`, {
2771
- installerStatePath: restoredBinding.installerStatePath || null,
2772
- relayAgentId: runtimeConfig?.relay?.agentId || null,
2773
- });
2774
- commitRuntimeBinding({
2775
- context: configuredContext,
2776
- runtime: runtimeResolution.runtime,
2777
- runtimeSource: runtimeResolution.runtimeSource,
2778
- accountId,
2779
- runtimeConfig,
2780
- bindingSource,
2781
- relayAgent,
2782
- });
2783
- }
2784
- }
2785
-
2786
- if (resolveRuntimeAppToken(runtimeConfig) && (!bindingSource || bindingSource === 'runtime_context')) {
2787
- bindingSource = 'configured_app_token';
2788
- }
2789
-
2790
- return {
2791
- ...configuredContext,
2792
- cfg: runtimeContext?.cfg || cfg,
2793
- accountId: runtimeConfig.accountId || accountId || null,
2794
- runtimeConfig,
2795
- runtime: runtimeResolution.runtime,
2796
- runtimeSource: runtimeResolution.runtimeSource,
2797
- agentId: configuredContext.agentId || runtimeConfig.relay?.agentId || null,
2798
- bindingSource,
2799
- relayAgent,
3130
+ bindingSource: runtimeContext?.deferredFailure ? 'runtime_context_deferred' : 'runtime_context',
2800
3131
  };
2801
3132
  }
2802
3133
 
2803
3134
  async function resolveBoundRuntimeContext(context = {}) {
2804
- const configuredContext = await resolveAccountViewRuntimeContext(context);
3135
+ const configuredContext = resolveConfiguredRuntimeContext(context);
2805
3136
  const cfg = configuredContext.cfg || {};
2806
3137
  const accountId = configuredContext.accountId || null;
2807
3138
  let runtimeConfig = configuredContext.runtimeConfig;
2808
- const runtimeResolution = resolvePluginRuntimeCandidate(
2809
- context.runtime || configuredContext.runtime || null,
2810
- );
3139
+ const runtimeResolution = resolvePluginRuntimeCandidate(context.runtime || null);
2811
3140
  const restoredBinding = await maybeRestoreRuntimeAppToken({
2812
3141
  runtime: runtimeResolution.runtime,
2813
3142
  accountId,
@@ -2830,7 +3159,7 @@ export function createClaworldChannelPlugin({
2830
3159
  runtime: runtimeResolution.runtime,
2831
3160
  runtimeSource: runtimeResolution.runtimeSource,
2832
3161
  agentId: configuredContext.agentId || runtimeConfig.relay?.agentId || null,
2833
- bindingSource: configuredContext.bindingSource || runtimeContext.bindingSource || 'runtime_context',
3162
+ bindingSource: 'runtime_context',
2834
3163
  };
2835
3164
  }
2836
3165
  const binding = await ensureAccountRelayBinding({ runtimeConfig, accountId });
@@ -3017,6 +3346,7 @@ export function createClaworldChannelPlugin({
3017
3346
  eventType: event?.eventType || null,
3018
3347
  target: event?.route?.target || null,
3019
3348
  deliveryId: event?.delivery?.deliveryId || null,
3349
+ eventId: event?.delivery?.eventId || null,
3020
3350
  sessionKey: event?.delivery?.sessionKey || null,
3021
3351
  });
3022
3352
 
@@ -3036,6 +3366,21 @@ export function createClaworldChannelPlugin({
3036
3366
  error: error?.message || String(error),
3037
3367
  });
3038
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`, {
3381
+ error: error?.message || String(error),
3382
+ });
3383
+ });
3039
3384
  }
3040
3385
  });
3041
3386
 
@@ -3167,7 +3512,7 @@ export function createClaworldChannelPlugin({
3167
3512
  }
3168
3513
 
3169
3514
  async function getRuntimePublicIdentity(context = {}) {
3170
- const resolvedContext = await resolveAccountViewRuntimeContext(context);
3515
+ const resolvedContext = resolveConfiguredRuntimeContext(context);
3171
3516
  return fetchPublicIdentity({
3172
3517
  runtimeConfig: resolvedContext.runtimeConfig,
3173
3518
  agentId: resolvedContext.agentId || null,
@@ -3178,10 +3523,7 @@ export function createClaworldChannelPlugin({
3178
3523
  }
3179
3524
 
3180
3525
  async function updateRuntimePublicIdentity(context = {}) {
3181
- const resolvedContext = await resolveAccountViewRuntimeContext(context);
3182
- const runtimeResolution = resolvePluginRuntimeCandidate(
3183
- context.runtime || resolvedContext.runtime || null,
3184
- );
3526
+ const resolvedContext = resolveConfiguredRuntimeContext(context);
3185
3527
  const updateResult = await updatePublicIdentity({
3186
3528
  runtimeConfig: resolvedContext.runtimeConfig,
3187
3529
  agentId: resolvedContext.agentId || null,
@@ -3222,6 +3564,7 @@ async function updateRuntimePublicIdentity(context = {}) {
3222
3564
  );
3223
3565
 
3224
3566
  if (shouldPersistRuntimeBinding) {
3567
+ const runtimeResolution = resolvePluginRuntimeCandidate(context.runtime || null);
3225
3568
  try {
3226
3569
  await persistRuntimeAppToken({
3227
3570
  runtime: runtimeResolution.runtime,
@@ -3235,19 +3578,23 @@ async function updateRuntimePublicIdentity(context = {}) {
3235
3578
  error: error?.message || String(error),
3236
3579
  });
3237
3580
  }
3238
- }
3239
3581
 
3240
- if (resolveRuntimeAppToken(boundRuntimeConfig) && nextAgentId) {
3241
- commitRuntimeBinding({
3242
- context: resolvedContext,
3243
- runtime: runtimeResolution.runtime,
3244
- runtimeSource: runtimeResolution.runtimeSource,
3582
+ rememberAccountBinding({
3245
3583
  runtimeConfig: boundRuntimeConfig,
3246
3584
  accountId: resolvedContext.accountId || boundRuntimeConfig.accountId || null,
3247
- bindingSource: runtimeActivation
3248
- ? 'activated_app_token'
3249
- : (resolvedContext.bindingSource || 'configured_app_token'),
3585
+ bindingSource: runtimeActivation ? 'activated_app_token' : 'configured_app_token',
3250
3586
  });
3587
+
3588
+ const accountKey = resolveAccountBindingKey(boundRuntimeConfig, resolvedContext.accountId || null);
3589
+ const currentRuntimeContext = accountRuntimeContexts.get(accountKey) || null;
3590
+ if (currentRuntimeContext) {
3591
+ accountRuntimeContexts.set(accountKey, {
3592
+ ...currentRuntimeContext,
3593
+ runtimeConfig: boundRuntimeConfig,
3594
+ deferredFailure: null,
3595
+ deferredErrorMessage: null,
3596
+ });
3597
+ }
3251
3598
  }
3252
3599
 
3253
3600
  const payload = updateResult && typeof updateResult === 'object' && !Array.isArray(updateResult)
@@ -3433,7 +3780,6 @@ async function generateRuntimeProfileCard(context = {}) {
3433
3780
  },
3434
3781
  helpers: {
3435
3782
  resolveToolRuntimeContext: resolveBoundRuntimeContext,
3436
- resolveToolAccountViewContext: resolveAccountViewRuntimeContext,
3437
3783
  pairing: {
3438
3784
  resolveAgentIdentity: async (context = {}) => resolveRelayAgentSummary({
3439
3785
  runtimeConfig: context.runtimeConfig || resolveClaworldRuntimeConfig(context.cfg || {}, context.accountId || null),