@openclaw/gateway-client 2026.9.2 → 2026.9.4

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.
@@ -1,12 +1,12 @@
1
- import { A as readSessionMessageSequence, C as reduceSessionProjection, D as normalizeSessionProjectionRunId, E as SessionMessageIdentity, F as normalizeDeviceMetadataForAuth, M as gatewayOriginScope, N as buildDeviceAuthPayload, O as readAssistantStreamSegmentIdentity, P as buildDeviceAuthPayloadV3, S as reconcileSessionProjectionSnapshot, T as SessionMessageEnvelope, _ as SessionProjectionState, a as GatewaySessionMessageSubscriptionOptions, b as isLocallyOptimisticSessionMessage, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionGatewayRunEvent, f as SessionProjectionRun, g as SessionProjectionSnapshotOptions, h as SessionProjectionScope, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as gatewayCredentialScope, k as readSessionMessageIdentity, l as SessionProjectionEntry, m as SessionProjectionRunTransition, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionRunStatus, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionEvent, v as createSessionProjection, w as reduceSessionProjectionRunEvent, x as projectLiveSessionMessage, y as hasSessionProjectionAcceptedFinal } from "./session-subscriptions-D2UdeJ0u.mjs";
1
+ import { A as readAssistantStreamSegmentIdentity, C as SessionProjectionRunTransition, D as SessionMessageEnvelope, E as readSessionProjectionFinalMessageIdentity, F as buildDeviceAuthPayload, I as buildDeviceAuthPayloadV3, L as normalizeDeviceMetadataForAuth, M as readSessionMessageSequence, N as gatewayCredentialScope, O as SessionMessageIdentity, P as gatewayOriginScope, S as SessionProjectionGatewayRunEvent, T as hasSessionProjectionAcceptedFinal, _ as isLocallyOptimisticSessionMessage, a as GatewaySessionMessageSubscriptionOptions, b as reduceSessionProjection, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionRun, f as SessionProjectionRunStatus, g as createSessionProjection, h as SessionProjectionState, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as readSessionMessageIdentity, k as normalizeSessionProjectionRunId, l as SessionProjectionEntry, m as SessionProjectionSnapshotOptions, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionScope, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionEvent, v as projectLiveSessionMessage, w as reduceSessionProjectionRunEvent, x as isSessionProjectionErrorMessage, y as reconcileSessionProjectionSnapshot } from "./session-subscriptions-BSQIANvX.mjs";
2
2
  import { a as GatewayBrowserDeviceTokenStore, c as resolveGatewayConnectScopes, i as GatewayBrowserDeviceTokenRecord, l as selectGatewayConnectAuth, n as GatewayBrowserDeviceAuthPlan, o as GatewayConnectAuthSelection, r as GatewayBrowserDeviceIdentity, s as buildGatewayConnectAuth, t as GatewayBrowserDeviceAuthLifecycle, u as shouldRetryGatewayWithDeviceToken } from "./browser-device-auth-DoPo-sPB.mjs";
3
3
  import { n as GatewayProtocolRequestOptions, r as GatewayProtocolRequestTimeoutError, t as GatewayProtocolRequestError } from "./protocol-request-B5gBmLgq.mjs";
4
4
  import { a as GatewayProtocolTiming, i as GatewayProtocolSocketHandlers, n as GatewayProtocolCloseContext, o as GatewayProtocolRequestTiming, r as GatewayProtocolSocket, t as GatewayProtocolClient } from "./protocol-client-DbX7wQED.mjs";
5
5
  import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, resolveSafeTimeoutDelayMs } from "./timeouts.mjs";
6
6
  import { ConnectParams, ErrorShape, EventFrame, HelloOk } from "@openclaw/gateway-protocol";
7
7
  export * from "@openclaw/gateway-protocol/connect-error-details";
8
- export * from "@openclaw/gateway-protocol/client-info";
9
8
  export * from "@openclaw/gateway-protocol/gateway-error-details";
9
+ export * from "@openclaw/gateway-protocol/client-info";
10
10
  export * from "@openclaw/gateway-protocol/startup-unavailable";
11
11
  export * from "@openclaw/gateway-protocol/version";
12
12
  //#region packages/gateway-client/src/reconnect-policy.d.ts
@@ -18,4 +18,4 @@ export declare function shouldPauseGatewayReconnect(params: {
18
18
  clientVersionMismatchIsTerminal?: boolean;
19
19
  }): boolean;
20
20
  //#endregion
21
- export { type ConnectParams, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type ErrorShape, type EventFrame, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayConnectAuthSelection, GatewayProtocolClient, type GatewayProtocolCloseContext, GatewayProtocolRequestError, type GatewayProtocolRequestOptions, GatewayProtocolRequestTimeoutError, type GatewayProtocolRequestTiming, type GatewayProtocolSocket, type GatewayProtocolSocketHandlers, type GatewayProtocolTiming, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, type HelloOk, type SessionMessageEnvelope, type SessionMessageIdentity, SessionProjectionEntry, SessionProjectionEvent, SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isLocallyOptimisticSessionMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken };
21
+ export { type ConnectParams, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, type ErrorShape, type EventFrame, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayConnectAuthSelection, GatewayProtocolClient, type GatewayProtocolCloseContext, GatewayProtocolRequestError, type GatewayProtocolRequestOptions, GatewayProtocolRequestTimeoutError, type GatewayProtocolRequestTiming, type GatewayProtocolSocket, type GatewayProtocolSocketHandlers, type GatewayProtocolTiming, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, type HelloOk, type SessionMessageEnvelope, type SessionMessageIdentity, SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken };
package/dist/browser.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { A as buildDeviceAuthPayloadV3, C as gatewayOriginScope, D as selectGatewayConnectAuth, E as resolveGatewayConnectScopes, O as shouldRetryGatewayWithDeviceToken, S as gatewayCredentialScope, T as buildGatewayConnectAuth, _ as shouldPauseGatewayReconnect, a as createSessionProjection, b as GatewayProtocolRequestTimeoutError, c as projectLiveSessionMessage, d as reduceSessionProjectionRunEvent, f as normalizeSessionProjectionRunId, h as readSessionMessageSequence, i as resetGatewaySessionMessageSubscriptionCoordinator, j as normalizeDeviceMetadataForAuth, k as buildDeviceAuthPayload, l as reconcileSessionProjectionSnapshot, m as readSessionMessageIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as hasSessionProjectionAcceptedFinal, p as readAssistantStreamSegmentIdentity, r as releaseGatewaySessionMessageSubscription, s as isLocallyOptimisticSessionMessage, t as GatewaySessionMessageSubscriptionCoordinator, u as reduceSessionProjection, v as GatewayProtocolClient, w as GatewayBrowserDeviceAuthLifecycle, y as GatewayProtocolRequestError } from "./session-subscriptions-C0VxZerW.mjs";
1
+ import { A as shouldRetryGatewayWithDeviceToken, D as buildGatewayConnectAuth, E as GatewayBrowserDeviceAuthLifecycle, M as buildDeviceAuthPayloadV3, N as normalizeDeviceMetadataForAuth, O as resolveGatewayConnectScopes, S as GatewayProtocolRequestTimeoutError, T as gatewayOriginScope, _ as readSessionMessageSequence, a as createSessionProjection, b as GatewayProtocolClient, c as reconcileSessionProjectionSnapshot, d as hasSessionProjectionAcceptedFinal, f as readSessionProjectionFinalMessageIdentity, g as readSessionMessageIdentity, h as readAssistantStreamSegmentIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as buildDeviceAuthPayload, k as selectGatewayConnectAuth, l as reduceSessionProjection, m as normalizeSessionProjectionRunId, n as getGatewaySessionMessageSubscriptionCoordinator, o as isLocallyOptimisticSessionMessage, p as isSessionProjectionErrorMessage, r as releaseGatewaySessionMessageSubscription, s as projectLiveSessionMessage, t as GatewaySessionMessageSubscriptionCoordinator, u as reduceSessionProjectionRunEvent, w as gatewayCredentialScope, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect } from "./session-subscriptions-DIcpqS8A.mjs";
2
2
  import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, resolveSafeTimeoutDelayMs } from "./timeouts.mjs";
3
3
  export * from "@openclaw/gateway-protocol/connect-error-details";
4
- export * from "@openclaw/gateway-protocol/client-info";
5
4
  export * from "@openclaw/gateway-protocol/gateway-error-details";
5
+ export * from "@openclaw/gateway-protocol/client-info";
6
6
  export * from "@openclaw/gateway-protocol/startup-unavailable";
7
7
  export * from "@openclaw/gateway-protocol/version";
8
- export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayProtocolClient, GatewayProtocolRequestError, GatewayProtocolRequestTimeoutError, GatewaySessionMessageSubscriptionCoordinator, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isLocallyOptimisticSessionMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldPauseGatewayReconnect, shouldRetryGatewayWithDeviceToken };
8
+ export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayProtocolClient, GatewayProtocolRequestError, GatewayProtocolRequestTimeoutError, GatewaySessionMessageSubscriptionCoordinator, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveGatewayConnectScopes, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldPauseGatewayReconnect, shouldRetryGatewayWithDeviceToken };
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { A as readSessionMessageSequence, C as reduceSessionProjection, D as normalizeSessionProjectionRunId, E as SessionMessageIdentity, F as normalizeDeviceMetadataForAuth, M as gatewayOriginScope, N as buildDeviceAuthPayload, O as readAssistantStreamSegmentIdentity, P as buildDeviceAuthPayloadV3, S as reconcileSessionProjectionSnapshot, T as SessionMessageEnvelope, _ as SessionProjectionState, a as GatewaySessionMessageSubscriptionOptions, b as isLocallyOptimisticSessionMessage, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionGatewayRunEvent, f as SessionProjectionRun, g as SessionProjectionSnapshotOptions, h as SessionProjectionScope, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as gatewayCredentialScope, k as readSessionMessageIdentity, l as SessionProjectionEntry, m as SessionProjectionRunTransition, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionRunStatus, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionEvent, v as createSessionProjection, w as reduceSessionProjectionRunEvent, x as projectLiveSessionMessage, y as hasSessionProjectionAcceptedFinal } from "./session-subscriptions-D2UdeJ0u.mjs";
1
+ import { A as readAssistantStreamSegmentIdentity, C as SessionProjectionRunTransition, D as SessionMessageEnvelope, E as readSessionProjectionFinalMessageIdentity, F as buildDeviceAuthPayload, I as buildDeviceAuthPayloadV3, L as normalizeDeviceMetadataForAuth, M as readSessionMessageSequence, N as gatewayCredentialScope, O as SessionMessageIdentity, P as gatewayOriginScope, S as SessionProjectionGatewayRunEvent, T as hasSessionProjectionAcceptedFinal, _ as isLocallyOptimisticSessionMessage, a as GatewaySessionMessageSubscriptionOptions, b as reduceSessionProjection, c as resetGatewaySessionMessageSubscriptionCoordinator, d as SessionProjectionRun, f as SessionProjectionRunStatus, g as createSessionProjection, h as SessionProjectionState, i as GatewaySessionMessageSubscriptionCoordinatorOptions, j as readSessionMessageIdentity, k as normalizeSessionProjectionRunId, l as SessionProjectionEntry, m as SessionProjectionSnapshotOptions, n as GatewaySessionMessageSubscription, o as getGatewaySessionMessageSubscriptionCoordinator, p as SessionProjectionScope, r as GatewaySessionMessageSubscriptionCoordinator, s as releaseGatewaySessionMessageSubscription, t as GatewaySessionMessageRequestClient, u as SessionProjectionEvent, v as projectLiveSessionMessage, w as reduceSessionProjectionRunEvent, x as isSessionProjectionErrorMessage, y as reconcileSessionProjectionSnapshot } from "./session-subscriptions-BSQIANvX.mjs";
2
2
  import { a as GatewayBrowserDeviceTokenStore, c as resolveGatewayConnectScopes, i as GatewayBrowserDeviceTokenRecord, l as selectGatewayConnectAuth, n as GatewayBrowserDeviceAuthPlan, o as GatewayConnectAuthSelection, r as GatewayBrowserDeviceIdentity, s as buildGatewayConnectAuth, t as GatewayBrowserDeviceAuthLifecycle, u as shouldRetryGatewayWithDeviceToken } from "./browser-device-auth-DoPo-sPB.mjs";
3
3
  import { i as isGatewayProtocolResponseError } from "./protocol-request-B5gBmLgq.mjs";
4
4
  import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, getConnectChallengeTimeoutMsFromEnv, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, startGatewayConnectTimeout } from "./timeouts.mjs";
5
- import { _ as GatewayClientRequestTimeoutError, a as startGatewayClientWithReadinessWait, b as GatewayClientRequestError, c as waitForEventLoopReady, d as GatewayClient, f as GatewayClientCloseInfo, g as GatewayClientRequestOptions, h as GatewayClientOptions, i as startGatewayClientWhenEventLoopReady, l as DeviceAuthTokenRecord, m as GatewayClientHostDeps, n as GatewayClientStartReadinessOptions, o as EventLoopReadyOptions, p as GatewayClientConnectionMetadata, r as GatewayClientStartable, s as EventLoopReadyResult, t as EventLoopReadyWaiter, u as DeviceIdentity, v as GatewayReconnectPausedInfo, y as isGatewayConnectAssemblyError } from "./readiness-uQKoJkl5.mjs";
5
+ import { _ as GatewayClientRequestTimeoutError, a as startGatewayClientWithReadinessWait, b as GatewayClientRequestError, c as waitForEventLoopReady, d as GatewayClient, f as GatewayClientCloseInfo, g as GatewayClientRequestOptions, h as GatewayClientOptions, i as startGatewayClientWhenEventLoopReady, l as DeviceAuthTokenRecord, m as GatewayClientHostDeps, n as GatewayClientStartReadinessOptions, o as EventLoopReadyOptions, p as GatewayClientConnectionMetadata, r as GatewayClientStartable, s as EventLoopReadyResult, t as EventLoopReadyWaiter, u as DeviceIdentity, v as GatewayReconnectPausedInfo, y as isGatewayConnectAssemblyError } from "./readiness-DabX0O0A.mjs";
6
6
  import { GatewayScopeUpgrade, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome } from "./scope-upgrade.mjs";
7
7
  //#region packages/gateway-client/src/cloudflare-access.d.ts
8
8
  export declare const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
@@ -14,4 +14,4 @@ export type CloudflareAccessCredentials = Readonly<{
14
14
  /** Build only the two headers Cloudflare Access defines for service-token auth. */
15
15
  export declare function buildCloudflareAccessHeaders(credentials: CloudflareAccessCredentials): Record<string, string>;
16
16
  //#endregion
17
- export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, DeviceAuthTokenRecord, DeviceIdentity, EventLoopReadyOptions, EventLoopReadyResult, EventLoopReadyWaiter, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayClient, GatewayClientCloseInfo, GatewayClientConnectionMetadata, GatewayClientHostDeps, GatewayClientOptions, GatewayClientRequestError, GatewayClientRequestOptions, GatewayClientRequestTimeoutError, GatewayClientStartReadinessOptions, GatewayClientStartable, GatewayConnectAuthSelection, GatewayReconnectPausedInfo, GatewayScopeUpgrade, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome, type SessionMessageEnvelope, type SessionMessageIdentity, SessionProjectionEntry, SessionProjectionEvent, SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, addSafeTimeoutDelayGraceMs, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
17
+ export { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, DeviceAuthTokenRecord, DeviceIdentity, EventLoopReadyOptions, EventLoopReadyResult, EventLoopReadyWaiter, GatewayBrowserDeviceAuthLifecycle, GatewayBrowserDeviceAuthPlan, GatewayBrowserDeviceIdentity, GatewayBrowserDeviceTokenRecord, GatewayBrowserDeviceTokenStore, GatewayClient, GatewayClientCloseInfo, GatewayClientConnectionMetadata, GatewayClientHostDeps, GatewayClientOptions, GatewayClientRequestError, GatewayClientRequestOptions, GatewayClientRequestTimeoutError, GatewayClientStartReadinessOptions, GatewayClientStartable, GatewayConnectAuthSelection, GatewayReconnectPausedInfo, GatewayScopeUpgrade, GatewaySessionMessageRequestClient, GatewaySessionMessageSubscription, GatewaySessionMessageSubscriptionCoordinator, GatewaySessionMessageSubscriptionCoordinatorOptions, GatewaySessionMessageSubscriptionOptions, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, ScopeUpgradeBinding, ScopeUpgradeOptions, ScopeUpgradeOutcome, type SessionMessageEnvelope, type SessionMessageIdentity, SessionProjectionEntry, SessionProjectionEvent, type SessionProjectionGatewayRunEvent, SessionProjectionRun, SessionProjectionRunStatus, type SessionProjectionRunTransition, SessionProjectionScope, SessionProjectionSnapshotOptions, SessionProjectionState, addSafeTimeoutDelayGraceMs, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
package/dist/index.mjs CHANGED
@@ -1,16 +1,17 @@
1
- import { A as buildDeviceAuthPayloadV3, C as gatewayOriginScope, D as selectGatewayConnectAuth, E as resolveGatewayConnectScopes, O as shouldRetryGatewayWithDeviceToken, S as gatewayCredentialScope, T as buildGatewayConnectAuth, _ as shouldPauseGatewayReconnect, a as createSessionProjection, b as GatewayProtocolRequestTimeoutError, c as projectLiveSessionMessage, d as reduceSessionProjectionRunEvent, f as normalizeSessionProjectionRunId, g as isRecord, h as readSessionMessageSequence, i as resetGatewaySessionMessageSubscriptionCoordinator, j as normalizeDeviceMetadataForAuth, k as buildDeviceAuthPayload, l as reconcileSessionProjectionSnapshot, m as readSessionMessageIdentity, n as getGatewaySessionMessageSubscriptionCoordinator, o as hasSessionProjectionAcceptedFinal, p as readAssistantStreamSegmentIdentity, r as releaseGatewaySessionMessageSubscription, s as isLocallyOptimisticSessionMessage, t as GatewaySessionMessageSubscriptionCoordinator, u as reduceSessionProjection, v as GatewayProtocolClient, w as GatewayBrowserDeviceAuthLifecycle, x as isGatewayProtocolResponseError, y as GatewayProtocolRequestError } from "./session-subscriptions-C0VxZerW.mjs";
1
+ import { A as shouldRetryGatewayWithDeviceToken, C as isGatewayProtocolResponseError, D as buildGatewayConnectAuth, E as GatewayBrowserDeviceAuthLifecycle, M as buildDeviceAuthPayloadV3, N as normalizeDeviceMetadataForAuth, O as resolveGatewayConnectScopes, S as GatewayProtocolRequestTimeoutError, T as gatewayOriginScope, _ as readSessionMessageSequence, a as createSessionProjection, b as GatewayProtocolClient, c as reconcileSessionProjectionSnapshot, d as hasSessionProjectionAcceptedFinal, f as readSessionProjectionFinalMessageIdentity, g as readSessionMessageIdentity, h as readAssistantStreamSegmentIdentity, i as resetGatewaySessionMessageSubscriptionCoordinator, j as buildDeviceAuthPayload, k as selectGatewayConnectAuth, l as reduceSessionProjection, m as normalizeSessionProjectionRunId, n as getGatewaySessionMessageSubscriptionCoordinator, o as isLocallyOptimisticSessionMessage, p as isSessionProjectionErrorMessage, r as releaseGatewaySessionMessageSubscription, s as projectLiveSessionMessage, t as GatewaySessionMessageSubscriptionCoordinator, u as reduceSessionProjectionRunEvent, v as isRecord, w as gatewayCredentialScope, x as GatewayProtocolRequestError, y as shouldPauseGatewayReconnect } from "./session-subscriptions-DIcpqS8A.mjs";
2
2
  import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, getConnectChallengeTimeoutMsFromEnv, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, startGatewayConnectTimeout } from "./timeouts.mjs";
3
3
  import { rawDataToString } from "./websocket-data.mjs";
4
4
  import { n as startGatewayClientWithReadinessWait, r as waitForEventLoopReady, t as startGatewayClientWhenEventLoopReady } from "./readiness-CrWxd4TI.mjs";
5
5
  import { GatewayScopeUpgrade } from "./scope-upgrade.mjs";
6
+ import { createRequire } from "node:module";
6
7
  import { ConnectErrorDetailCodes, formatConnectErrorMessage, readConnectErrorDetailCode } from "@openclaw/gateway-protocol/connect-error-details";
7
8
  import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "@openclaw/gateway-protocol/client-info";
8
9
  import { resolveGatewayStartupRetryAfterMs } from "@openclaw/gateway-protocol/startup-unavailable";
9
10
  import { MIN_CLIENT_PROTOCOL_VERSION, MIN_NODE_PROTOCOL_VERSION, MIN_PROBE_PROTOCOL_VERSION, PROTOCOL_VERSION } from "@openclaw/gateway-protocol/version";
10
11
  import { randomUUID } from "node:crypto";
11
- import { WebSocket } from "ws";
12
12
  import ipaddr from "ipaddr.js";
13
13
  import { TLSSocket } from "node:tls";
14
+ import path from "node:path";
14
15
  //#region packages/normalization-core/src/string-coerce.ts
15
16
  /** Trims string input and returns null for non-strings or empty strings. */
16
17
  function normalizeNullableString(value) {
@@ -535,6 +536,10 @@ function applyGatewayWebSocketTlsPin(options, expectedFingerprint, normalize = n
535
536
  };
536
537
  }
537
538
  //#endregion
539
+ //#region packages/gateway-client/src/websocket.ts
540
+ const require = createRequire(import.meta.url);
541
+ const { WebSocket } = require(path.join(path.dirname(require.resolve("ws/package.json")), "index.js"));
542
+ //#endregion
538
543
  //#region packages/gateway-client/src/client.ts
539
544
  const DEFAULT_HOST_DEPS = {
540
545
  loadOrCreateDeviceIdentity: () => void 0,
@@ -739,6 +744,11 @@ var GatewayClient = class {
739
744
  rethrowSocketFactoryError: (error) => error instanceof GatewayClientTransportPolicyError
740
745
  });
741
746
  }
747
+ /** Current transport state, including CLOSING before the close callback fires.
748
+ * This is not authentication or readiness evidence on its own. */
749
+ get connected() {
750
+ return !this.stopped && this.protocol.connected;
751
+ }
742
752
  getConnectionMetadata() {
743
753
  return {
744
754
  clientName: this.opts.clientName,
@@ -1344,4 +1354,4 @@ function buildCloudflareAccessHeaders(credentials) {
1344
1354
  };
1345
1355
  }
1346
1356
  //#endregion
1347
- export { CF_ACCESS_CLIENT_ID_HEADER, CF_ACCESS_CLIENT_SECRET_HEADER, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayClient, GatewayClientRequestError, GatewayClientRequestTimeoutError, GatewayScopeUpgrade, GatewaySessionMessageSubscriptionCoordinator, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, buildCloudflareAccessHeaders, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
1357
+ export { CF_ACCESS_CLIENT_ID_HEADER, CF_ACCESS_CLIENT_SECRET_HEADER, DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, GatewayBrowserDeviceAuthLifecycle, GatewayClient, GatewayClientRequestError, GatewayClientRequestTimeoutError, GatewayScopeUpgrade, GatewaySessionMessageSubscriptionCoordinator, MAX_CONNECT_CHALLENGE_TIMEOUT_MS, MAX_SAFE_TIMEOUT_DELAY_MS, MIN_CONNECT_CHALLENGE_TIMEOUT_MS, addSafeTimeoutDelayGraceMs, buildCloudflareAccessHeaders, buildDeviceAuthPayload, buildDeviceAuthPayloadV3, buildGatewayConnectAuth, clampConnectChallengeTimeoutMs, clearGatewayConnectTimeout, createSessionProjection, gatewayCredentialScope, gatewayOriginScope, getConnectChallengeTimeoutMsFromEnv, getGatewaySessionMessageSubscriptionCoordinator, hasSessionProjectionAcceptedFinal, isGatewayConnectAssemblyError, isGatewayProtocolResponseError, isLocallyOptimisticSessionMessage, isSessionProjectionErrorMessage, normalizeDeviceMetadataForAuth, normalizeSessionProjectionRunId, projectLiveSessionMessage, readAssistantStreamSegmentIdentity, readSessionMessageIdentity, readSessionMessageSequence, readSessionProjectionFinalMessageIdentity, reconcileSessionProjectionSnapshot, reduceSessionProjection, reduceSessionProjectionRunEvent, releaseGatewaySessionMessageSubscription, resetGatewaySessionMessageSubscriptionCoordinator, resolveConnectChallengeTimeoutMs, resolveFiniteTimeoutDelayMs, resolveGatewayConnectScopes, resolvePreauthHandshakeTimeoutMs, resolveSafeTimeoutDelayMs, selectGatewayConnectAuth, shouldRetryGatewayWithDeviceToken, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait, startGatewayConnectTimeout, waitForEventLoopReady };
@@ -152,6 +152,9 @@ declare class GatewayClient {
152
152
  private transportValidated;
153
153
  private suppressedTransientPreHelloCleanCloses;
154
154
  constructor(opts: GatewayClientOptions);
155
+ /** Current transport state, including CLOSING before the close callback fires.
156
+ * This is not authentication or readiness evidence on its own. */
157
+ get connected(): boolean;
155
158
  getConnectionMetadata(): GatewayClientConnectionMetadata;
156
159
  updateNodeManifest(manifest: {
157
160
  caps: string[];
@@ -1,2 +1,2 @@
1
- import { a as startGatewayClientWithReadinessWait, i as startGatewayClientWhenEventLoopReady, n as GatewayClientStartReadinessOptions, r as GatewayClientStartable, t as EventLoopReadyWaiter } from "./readiness-uQKoJkl5.mjs";
1
+ import { a as startGatewayClientWithReadinessWait, i as startGatewayClientWhenEventLoopReady, n as GatewayClientStartReadinessOptions, r as GatewayClientStartable, t as EventLoopReadyWaiter } from "./readiness-DabX0O0A.mjs";
2
2
  export { EventLoopReadyWaiter, GatewayClientStartReadinessOptions, GatewayClientStartable, startGatewayClientWhenEventLoopReady, startGatewayClientWithReadinessWait };
@@ -57,6 +57,35 @@ declare function readAssistantStreamSegmentIdentity(message: unknown): {
57
57
  runId?: string;
58
58
  } | undefined;
59
59
  //#endregion
60
+ //#region packages/gateway-client/src/session-projection-final-identity.d.ts
61
+ type TerminalProjectionRun = {
62
+ message?: unknown;
63
+ status: string;
64
+ acceptedFinalMessageIdentities?: readonly string[];
65
+ };
66
+ /** Read stable persisted identity first, falling back to canonical display content. */
67
+ declare function readSessionProjectionFinalMessageIdentity(message: unknown): string | null;
68
+ /** Check whether a run has already accepted the same terminal reply. */
69
+ declare function hasSessionProjectionAcceptedFinal(run: TerminalProjectionRun | undefined, message: unknown): boolean;
70
+ //#endregion
71
+ //#region packages/gateway-client/src/session-projection-run-event.d.ts
72
+ type SessionProjectionGatewayRunEvent = {
73
+ state?: unknown;
74
+ yielded?: unknown;
75
+ seq?: unknown;
76
+ } & Partial<Record<"runId" | "message" | "stopReason" | "errorKind" | "errorMessage", unknown>>;
77
+ type SessionProjectionRunTransition = {
78
+ projection: SessionProjectionState;
79
+ previousRun: SessionProjectionRun | undefined;
80
+ currentRun: SessionProjectionRun | undefined;
81
+ };
82
+ /** Normalizes Gateway run envelopes once for every browser and terminal adapter. */
83
+ declare function reduceSessionProjectionRunEvent(projection: SessionProjectionState, event: SessionProjectionGatewayRunEvent, scope?: SessionProjectionScope): SessionProjectionRunTransition | null;
84
+ //#endregion
85
+ //#region packages/gateway-client/src/session-projection-message-content.d.ts
86
+ /** Diagnostic-only error projections can be retired when their run resumes. */
87
+ declare function isSessionProjectionErrorMessage(message: unknown, errorMessage?: string): boolean;
88
+ //#endregion
60
89
  //#region packages/gateway-client/src/session-projection.d.ts
61
90
  type SessionProjectionScope = {
62
91
  sessionKey?: string;
@@ -71,22 +100,18 @@ type SessionProjectionSnapshotOptions = {
71
100
  type SessionProjectionRunStatus = "streaming" | "completed" | "error" | "aborted" | "timeout" | "yielded";
72
101
  type SessionProjectionRun = {
73
102
  runId: string;
103
+ seq?: number;
74
104
  status: SessionProjectionRunStatus;
75
105
  message?: unknown;
76
106
  acceptedFinalMessageIdentities?: readonly string[];
107
+ inferredSnapshotTerminal?: {
108
+ entry: SessionProjectionEntry;
109
+ matchedIdentity: SessionMessageIdentity;
110
+ };
77
111
  stopReason?: string;
78
112
  errorKind?: string;
79
113
  errorMessage?: string;
80
114
  };
81
- type SessionProjectionGatewayRunEvent = {
82
- state?: unknown;
83
- yielded?: unknown;
84
- } & Partial<Record<"runId" | "message" | "stopReason" | "errorKind" | "errorMessage", unknown>>;
85
- type SessionProjectionRunTransition = {
86
- projection: SessionProjectionState;
87
- previousRun: SessionProjectionRun | undefined;
88
- currentRun: SessionProjectionRun | undefined;
89
- };
90
115
  type SessionProjectionEntry = {
91
116
  message: unknown;
92
117
  identity: SessionMessageIdentity | null;
@@ -129,6 +154,7 @@ type SessionProjectionEvent = ScopedSessionProjectionEvent & ({
129
154
  } | {
130
155
  type: "runDelta";
131
156
  runId: string;
157
+ seq?: number;
132
158
  message?: unknown;
133
159
  } | (Omit<SessionProjectionRun, "acceptedFinalMessageIdentities"> & {
134
160
  type: "runTerminal";
@@ -146,12 +172,8 @@ declare function createSessionProjection(scope?: SessionProjectionScope, message
146
172
  declare function projectLiveSessionMessage(state: SessionProjectionState, message: unknown, envelope?: SessionMessageEnvelope, scope?: SessionProjectionScope): SessionProjectionState;
147
173
  /** Only observed live events and this client's pending turns may survive an older snapshot. */
148
174
  declare function reconcileSessionProjectionSnapshot(state: SessionProjectionState, messages: readonly unknown[], scope?: SessionProjectionScope, options?: SessionProjectionSnapshotOptions): SessionProjectionState;
149
- /** Replayed finals are recognized against this run's bounded canonical terminal history. */
150
- declare function hasSessionProjectionAcceptedFinal(run: SessionProjectionRun | undefined, message: unknown): boolean;
151
175
  /** Reduces durable events, snapshots, and transport lifecycle without client-specific policy. */
152
176
  declare function reduceSessionProjection(state: SessionProjectionState, event: SessionProjectionEvent): SessionProjectionState;
153
- /** Normalizes Gateway run envelopes once for every browser and terminal adapter. */
154
- declare function reduceSessionProjectionRunEvent(projection: SessionProjectionState, event: SessionProjectionGatewayRunEvent, scope?: SessionProjectionScope): SessionProjectionRunTransition | null;
155
177
  //#endregion
156
178
  //#region packages/gateway-client/src/session-subscriptions.d.ts
157
179
  type GatewaySessionMessageRequestClient = {
@@ -187,4 +209,4 @@ declare function getGatewaySessionMessageSubscriptionCoordinator(client: Gateway
187
209
  declare function resetGatewaySessionMessageSubscriptionCoordinator(client: GatewaySessionMessageRequestClient): void;
188
210
  declare function releaseGatewaySessionMessageSubscription(subscription: GatewaySessionMessageSubscription): Promise<void>;
189
211
  //#endregion
190
- export { readSessionMessageSequence as A, reduceSessionProjection as C, normalizeSessionProjectionRunId as D, SessionMessageIdentity as E, normalizeDeviceMetadataForAuth as F, gatewayOriginScope as M, buildDeviceAuthPayload as N, readAssistantStreamSegmentIdentity as O, buildDeviceAuthPayloadV3 as P, reconcileSessionProjectionSnapshot as S, SessionMessageEnvelope as T, SessionProjectionState as _, GatewaySessionMessageSubscriptionOptions as a, isLocallyOptimisticSessionMessage as b, resetGatewaySessionMessageSubscriptionCoordinator as c, SessionProjectionGatewayRunEvent as d, SessionProjectionRun as f, SessionProjectionSnapshotOptions as g, SessionProjectionScope as h, GatewaySessionMessageSubscriptionCoordinatorOptions as i, gatewayCredentialScope as j, readSessionMessageIdentity as k, SessionProjectionEntry as l, SessionProjectionRunTransition as m, GatewaySessionMessageSubscription as n, getGatewaySessionMessageSubscriptionCoordinator as o, SessionProjectionRunStatus as p, GatewaySessionMessageSubscriptionCoordinator as r, releaseGatewaySessionMessageSubscription as s, GatewaySessionMessageRequestClient as t, SessionProjectionEvent as u, createSessionProjection as v, reduceSessionProjectionRunEvent as w, projectLiveSessionMessage as x, hasSessionProjectionAcceptedFinal as y };
212
+ export { readAssistantStreamSegmentIdentity as A, SessionProjectionRunTransition as C, SessionMessageEnvelope as D, readSessionProjectionFinalMessageIdentity as E, buildDeviceAuthPayload as F, buildDeviceAuthPayloadV3 as I, normalizeDeviceMetadataForAuth as L, readSessionMessageSequence as M, gatewayCredentialScope as N, SessionMessageIdentity as O, gatewayOriginScope as P, SessionProjectionGatewayRunEvent as S, hasSessionProjectionAcceptedFinal as T, isLocallyOptimisticSessionMessage as _, GatewaySessionMessageSubscriptionOptions as a, reduceSessionProjection as b, resetGatewaySessionMessageSubscriptionCoordinator as c, SessionProjectionRun as d, SessionProjectionRunStatus as f, createSessionProjection as g, SessionProjectionState as h, GatewaySessionMessageSubscriptionCoordinatorOptions as i, readSessionMessageIdentity as j, normalizeSessionProjectionRunId as k, SessionProjectionEntry as l, SessionProjectionSnapshotOptions as m, GatewaySessionMessageSubscription as n, getGatewaySessionMessageSubscriptionCoordinator as o, SessionProjectionScope as p, GatewaySessionMessageSubscriptionCoordinator as r, releaseGatewaySessionMessageSubscription as s, GatewaySessionMessageRequestClient as t, SessionProjectionEvent as u, projectLiveSessionMessage as v, reduceSessionProjectionRunEvent as w, isSessionProjectionErrorMessage as x, reconcileSessionProjectionSnapshot as y };
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS, clearGatewayConnectTimeout, resolveSafeTimeoutDelayMs, startGatewayConnectTimeout } from "./timeouts.mjs";
2
2
  import { ConnectErrorDetailCodes, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readPairingConnectErrorDetails } from "@openclaw/gateway-protocol/connect-error-details";
3
3
  import { isGatewayEventFrame, isGatewayResponseFrame } from "@openclaw/gateway-protocol/frame-guards";
4
+ import { GATEWAY_ASSISTANT_ERROR_FALLBACK_TEXT } from "@openclaw/gateway-protocol/gateway-error-details";
4
5
  //#region packages/gateway-client/src/device-auth.ts
5
6
  function normalizeDeviceMetadataForAuth(value) {
6
7
  if (typeof value !== "string") return "";
@@ -482,7 +483,8 @@ var GatewayPendingRequests = class {
482
483
  return this.pending.size > 0;
483
484
  }
484
485
  get hasUnboundedPending() {
485
- return [...this.pending.values()].some((pending) => pending.unbounded);
486
+ for (const pending of this.pending.values()) if (pending.unbounded) return true;
487
+ return false;
486
488
  }
487
489
  request(sender, method, params, options) {
488
490
  let id;
@@ -578,8 +580,8 @@ var GatewayPendingRequests = class {
578
580
  pending.reject(error);
579
581
  }
580
582
  flush(error) {
581
- const retired = [...this.pending];
582
- this.pending.clear();
583
+ const retired = this.pending;
584
+ this.pending = /* @__PURE__ */ new Map();
583
585
  this.requestSequence = 0;
584
586
  for (const [id, pending] of retired) {
585
587
  pending.cleanup?.();
@@ -594,9 +596,7 @@ var GatewayPendingRequests = class {
594
596
  finishTiming(id, pending, ok, errorCode) {
595
597
  const endedAtMs = this.opts.nowMs();
596
598
  try {
597
- const onTiming = this.opts.onTiming;
598
- if (onTiming === void 0 || onTiming === null) return;
599
- Reflect.apply(onTiming, this.opts, [{
599
+ this.opts.onTiming?.({
600
600
  id,
601
601
  method: pending.method,
602
602
  ok,
@@ -604,7 +604,7 @@ var GatewayPendingRequests = class {
604
604
  startedAtMs: pending.startedAtMs,
605
605
  endedAtMs,
606
606
  errorCode
607
- }]);
607
+ });
608
608
  } catch (error) {
609
609
  this.opts.onCallbackError?.("request timing", error);
610
610
  }
@@ -1032,6 +1032,66 @@ function asNullableRecord(value) {
1032
1032
  return isRecord(value) ? value : null;
1033
1033
  }
1034
1034
  //#endregion
1035
+ //#region packages/normalization-core/src/stable-stringify.ts
1036
+ const preserveString = (value) => value;
1037
+ /** Deterministically stringifies values, optionally normalizing strings before key ordering. */
1038
+ function stableStringify(value, normalizeString = preserveString) {
1039
+ return stringifyStableValue(value, /* @__PURE__ */ new WeakSet(), normalizeString);
1040
+ }
1041
+ function stringifyStableValue(value, stack, normalizeString) {
1042
+ if (value === null || value === void 0) return String(value);
1043
+ if (typeof value === "number" && !Number.isFinite(value)) return JSON.stringify(String(value));
1044
+ if (typeof value === "bigint") return JSON.stringify(value.toString());
1045
+ if (typeof value === "string") return JSON.stringify(normalizeString(value));
1046
+ if (typeof value !== "object") return JSON.stringify(value) ?? "null";
1047
+ if (stack.has(value)) return JSON.stringify("[Circular]");
1048
+ stack.add(value);
1049
+ try {
1050
+ return stringifyObjectValue(value, stack, normalizeString);
1051
+ } finally {
1052
+ stack.delete(value);
1053
+ }
1054
+ }
1055
+ function stringifyObjectValue(value, stack, normalizeString) {
1056
+ if (value instanceof Error) return stringifyStableValue({
1057
+ name: value.name,
1058
+ message: value.message,
1059
+ stack: value.stack
1060
+ }, stack, normalizeString);
1061
+ if (value instanceof Uint8Array) return stringifyStableValue({
1062
+ type: "Uint8Array",
1063
+ data: encodeBase64(value)
1064
+ }, stack, normalizeString);
1065
+ if (Array.isArray(value)) {
1066
+ const serializedEntries = [];
1067
+ for (const entry of value) serializedEntries.push(stringifyStableValue(entry, stack, normalizeString));
1068
+ return `[${serializedEntries.join(",")}]`;
1069
+ }
1070
+ const record = value;
1071
+ if (normalizeString === preserveString) {
1072
+ const fields = [];
1073
+ for (const key of Object.keys(record).toSorted()) fields.push(`${JSON.stringify(key)}:${stringifyStableValue(record[key], stack, normalizeString)}`);
1074
+ return `{${fields.join(",")}}`;
1075
+ }
1076
+ const entries = Object.keys(record).map((key) => ({
1077
+ key,
1078
+ normalizedKey: normalizeString(key)
1079
+ })).toSorted((left, right) => {
1080
+ return compareStableStrings(left.normalizedKey, right.normalizedKey) || compareStableStrings(left.key, right.key);
1081
+ });
1082
+ const serializedFields = [];
1083
+ for (const { key, normalizedKey } of entries) serializedFields.push(`${JSON.stringify(normalizedKey)}:${stringifyStableValue(record[key], stack, normalizeString)}`);
1084
+ return `{${serializedFields.join(",")}}`;
1085
+ }
1086
+ function encodeBase64(value) {
1087
+ let binary = "";
1088
+ for (const byte of value) binary += String.fromCharCode(byte);
1089
+ return btoa(binary);
1090
+ }
1091
+ function compareStableStrings(left, right) {
1092
+ return left < right ? -1 : left > right ? 1 : 0;
1093
+ }
1094
+ //#endregion
1035
1095
  //#region packages/gateway-client/src/session-projection-message-identity.ts
1036
1096
  function readSessionProjectionString(value) {
1037
1097
  return typeof value === "string" ? value.trim() || null : null;
@@ -1057,6 +1117,9 @@ function readSessionMessageIdentity(message, envelope) {
1057
1117
  const importedFrom = readSessionProjectionString(metadata?.importedFrom);
1058
1118
  const cliSessionId = readSessionProjectionString(metadata?.cliSessionId);
1059
1119
  const externalId = readSessionProjectionString(metadata?.externalId);
1120
+ const position = asNullableRecord(metadata?.transcriptPosition);
1121
+ const positionSource = readSessionProjectionString(position?.source);
1122
+ const isImported = !(positionSource !== null && positionSource.length <= 128 && typeof position?.rawSeq === "number" && Number.isSafeInteger(position.rawSeq) && position.rawSeq >= 0) && Boolean(importedFrom || cliSessionId || externalId);
1060
1123
  const idempotencyKey = readSessionProjectionString(metadata?.idempotencyKey) ?? readSessionProjectionString(record.idempotencyKey) ?? readSessionProjectionString(envelope?.idempotencyKey) ?? readSessionProjectionString(envelope?.clientRunId);
1061
1124
  const persistedRunId = normalizeSessionProjectionRunId(idempotencyKey);
1062
1125
  const envelopeRunId = normalizeSessionProjectionRunId(envelope?.runId);
@@ -1073,8 +1136,8 @@ function readSessionMessageIdentity(message, envelope) {
1073
1136
  idempotencyKey,
1074
1137
  sendId: role === "user" ? persistedRunId ?? runId : null,
1075
1138
  runId,
1076
- isImported: Boolean(importedFrom || cliSessionId || externalId),
1077
- externalSource: importedFrom && cliSessionId && externalId ? JSON.stringify([
1139
+ isImported,
1140
+ externalSource: isImported && importedFrom && cliSessionId && externalId ? JSON.stringify([
1078
1141
  importedFrom,
1079
1142
  cliSessionId,
1080
1143
  externalId
@@ -1094,11 +1157,157 @@ function readAssistantStreamSegmentIdentity(message) {
1094
1157
  } : void 0;
1095
1158
  }
1096
1159
  //#endregion
1160
+ //#region packages/gateway-client/src/session-projection-message-content.ts
1161
+ function readSessionMessageDisplayContent(message) {
1162
+ const record = asNullableRecord(message);
1163
+ const content = typeof message === "string" ? message : record?.content;
1164
+ const media = asNullableRecord(record?.["__openclaw"])?.media;
1165
+ let hasNonText = Array.isArray(media) && media.length > 0;
1166
+ const texts = [];
1167
+ for (const block of Array.isArray(content) ? content : [content]) {
1168
+ const entry = asNullableRecord(block);
1169
+ if (entry && entry.type !== "text" && entry.type !== "input_text" && entry.type !== "output_text") {
1170
+ hasNonText ||= entry.type !== "thinking" && entry.type !== "reasoning" && entry.type !== "redacted_thinking";
1171
+ continue;
1172
+ }
1173
+ const text = readSessionProjectionString(entry ? entry.text : block);
1174
+ if (text) texts.push(text);
1175
+ }
1176
+ const fallback = texts.length === 0 ? readSessionProjectionString(record?.text) : null;
1177
+ return {
1178
+ text: fallback ?? texts.join("\n"),
1179
+ hasNonText,
1180
+ usesFallbackText: fallback !== null
1181
+ };
1182
+ }
1183
+ /** Check whether a projected message has text or another displayable block. */
1184
+ function hasDisplayableSessionMessage(message) {
1185
+ const { text, hasNonText } = readSessionMessageDisplayContent(message);
1186
+ return Boolean(text) || hasNonText;
1187
+ }
1188
+ function normalizeChatErrorComparisonText(text) {
1189
+ return text.trim().replace(/^⚠️\s*/u, "").replace(/^Error:\s*/iu, "").replace(/\s+/gu, " ").trim();
1190
+ }
1191
+ /** Diagnostic-only error projections can be retired when their run resumes. */
1192
+ function isSessionProjectionErrorMessage(message, errorMessage) {
1193
+ const role = asNullableRecord(message)?.role;
1194
+ if (typeof role === "string" && role.trim().toLowerCase() !== "assistant") return false;
1195
+ const { text, hasNonText } = readSessionMessageDisplayContent(message);
1196
+ const normalizedText = normalizeChatErrorComparisonText(text);
1197
+ return !hasNonText && (!normalizedText || normalizedText === "[assistant turn failed before producing content]" || normalizedText === GATEWAY_ASSISTANT_ERROR_FALLBACK_TEXT || normalizedText === normalizeChatErrorComparisonText(errorMessage ?? ""));
1198
+ }
1199
+ //#endregion
1200
+ //#region packages/gateway-client/src/session-projection-final-identity.ts
1201
+ /** Terminal identity rules used to reconcile live and durable assistant projections. */
1202
+ function readPersistedFinalIdentity(message) {
1203
+ const identity = readSessionMessageIdentity(message);
1204
+ if (identity?.externalSource) return `import:${identity.role}:${identity.externalSource}`;
1205
+ if (identity?.id && !identity.isImported) return `id:${identity.role}:${identity.id}`;
1206
+ if (identity?.sequence !== null && identity?.sequence !== void 0) return `seq:${identity.role}:${identity.sequence}`;
1207
+ return null;
1208
+ }
1209
+ function hasCompatiblePersistedFinalIdentity(currentMessage, incomingMessage) {
1210
+ const current = readSessionMessageIdentity(currentMessage);
1211
+ const incoming = readSessionMessageIdentity(incomingMessage);
1212
+ if (!current || !incoming || current.role !== incoming.role) return false;
1213
+ if (current.isImported || incoming.isImported) {
1214
+ if (!current.isImported || !incoming.isImported) return false;
1215
+ if (current.externalSource && incoming.externalSource) return current.externalSource === incoming.externalSource;
1216
+ return current.sequence !== null && incoming.sequence !== null && current.sequence === incoming.sequence;
1217
+ }
1218
+ if (current.id && incoming.id) return current.id === incoming.id;
1219
+ return current.sequence !== null && incoming.sequence !== null && current.sequence === incoming.sequence;
1220
+ }
1221
+ function readFinalContentIdentity(message) {
1222
+ const display = readSessionMessageDisplayContent(message);
1223
+ if (!display.text && !display.hasNonText) return null;
1224
+ const identity = readSessionMessageIdentity(message);
1225
+ const record = asNullableRecord(message);
1226
+ const metadata = asNullableRecord(record?.["__openclaw"]);
1227
+ try {
1228
+ return `content:${stableStringify([
1229
+ identity?.role ?? "assistant",
1230
+ display.text,
1231
+ display.hasNonText ? record?.content ?? null : null,
1232
+ metadata?.media ?? null,
1233
+ identity?.isImported ? [
1234
+ metadata?.importedFrom ?? null,
1235
+ metadata?.cliSessionId ?? null,
1236
+ metadata?.externalId ?? null
1237
+ ] : null
1238
+ ])}`;
1239
+ } catch {
1240
+ return null;
1241
+ }
1242
+ }
1243
+ function hasTerminalStopReason(message) {
1244
+ const stopReason = asNullableRecord(message)?.stopReason;
1245
+ return stopReason === "stop" || stopReason === "length" || stopReason === "error" || stopReason === "aborted" || stopReason === "end_turn";
1246
+ }
1247
+ function hasCompletedRunSnapshotContext(entry, snapshot, runId) {
1248
+ if (!runId || entry.identity?.runId !== runId) return false;
1249
+ const entryIndex = snapshot.indexOf(entry);
1250
+ if (entryIndex < 0) return false;
1251
+ const hasEarlierUser = snapshot.slice(0, entryIndex).some((candidate) => candidate.identity?.role === "user" && candidate.identity.runId === runId);
1252
+ const hasLaterAssistant = snapshot.slice(entryIndex + 1).some((candidate) => candidate.identity?.role === "assistant" && candidate.identity.runId === runId);
1253
+ return hasEarlierUser && !hasLaterAssistant;
1254
+ }
1255
+ /** Read stable persisted identity first, falling back to canonical display content. */
1256
+ function readSessionProjectionFinalMessageIdentity(message) {
1257
+ if (!hasDisplayableSessionMessage(message)) return null;
1258
+ return readPersistedFinalIdentity(message) ?? readFinalContentIdentity(message);
1259
+ }
1260
+ /** Check whether a displayable terminal may recover a prior empty terminal. */
1261
+ function canRecoverSessionProjectionFinal(currentMessage, incomingMessage) {
1262
+ if (hasDisplayableSessionMessage(currentMessage)) return false;
1263
+ return readPersistedFinalIdentity(currentMessage) === null || hasCompatiblePersistedFinalIdentity(currentMessage, incomingMessage);
1264
+ }
1265
+ /** Check whether a run has already accepted the same terminal reply. */
1266
+ function hasSessionProjectionAcceptedFinal(run, message) {
1267
+ const identity = readSessionProjectionFinalMessageIdentity(message);
1268
+ return Boolean(identity && run && (run.acceptedFinalMessageIdentities?.includes(identity) || readSessionProjectionFinalMessageIdentity(run.message) === identity));
1269
+ }
1270
+ /** Match an unsequenced live terminal to exactly one durable same-run terminal row. */
1271
+ function findUniqueSnapshotTerminalMatch(current, matches, run, snapshot) {
1272
+ if (!current.live || current.identity?.role !== "assistant" || current.identity.id || current.identity.sequence !== null || !run || run.status === "streaming") return null;
1273
+ const terminalContent = readFinalContentIdentity(current.message);
1274
+ if (!terminalContent || readFinalContentIdentity(run.message) !== terminalContent) return null;
1275
+ const durableTerminalMatches = matches.filter((entry) => {
1276
+ return (asNullableRecord(asNullableRecord(entry.message)?.["__openclaw"])?.runTerminal === true || entry.identity?.runId === current.identity?.runId && hasTerminalStopReason(entry.message) || hasCompletedRunSnapshotContext(entry, snapshot, current.identity?.runId ?? null)) && readFinalContentIdentity(entry.message) === terminalContent;
1277
+ });
1278
+ const entry = durableTerminalMatches.length === 1 ? durableTerminalMatches[0] : void 0;
1279
+ if (!entry) return null;
1280
+ return {
1281
+ entry,
1282
+ inferred: asNullableRecord(asNullableRecord(entry.message)?.["__openclaw"])?.runTerminal !== true && !hasTerminalStopReason(entry.message)
1283
+ };
1284
+ }
1285
+ /** Check whether ordinary single-match promotion needs terminal-content verification. */
1286
+ function isUnsequencedLiveTerminal(current, run) {
1287
+ return Boolean(current.live && current.identity?.role === "assistant" && !current.identity.id && current.identity.sequence === null && run && run.status !== "streaming" && readFinalContentIdentity(current.message) === readFinalContentIdentity(run.message));
1288
+ }
1289
+ //#endregion
1290
+ //#region packages/gateway-client/src/session-projection-run-retention.ts
1291
+ /** Bounded retention for completed and active session projection runs. */
1292
+ const MAX_TRACKED_SESSION_RUNS = 200;
1293
+ const RETAINED_SESSION_RUNS = 150;
1294
+ /** Retain every active run and the newest completed runs within the projection bound. */
1295
+ function retainSessionProjectionRuns(runs) {
1296
+ const entries = Object.entries(runs);
1297
+ if (entries.length <= MAX_TRACKED_SESSION_RUNS) return runs;
1298
+ const active = entries.filter(([, run]) => run.status === "streaming");
1299
+ const terminal = entries.filter(([, run]) => run.status !== "streaming");
1300
+ const terminalLimit = Math.max(0, RETAINED_SESSION_RUNS - active.length);
1301
+ const retainedTerminal = terminalLimit > 0 ? terminal.slice(-terminalLimit) : [];
1302
+ return Object.fromEntries([...active, ...retainedTerminal]);
1303
+ }
1304
+ //#endregion
1097
1305
  //#region packages/gateway-client/src/session-projection-run-event.ts
1098
1306
  function readNonemptyString(value) {
1099
1307
  return typeof value === "string" ? value.trim() || null : null;
1100
1308
  }
1101
- function reduceSessionProjectionRunEventImpl(projection, event, scope = {}) {
1309
+ /** Normalizes Gateway run envelopes once for every browser and terminal adapter. */
1310
+ function reduceSessionProjectionRunEvent(projection, event, scope = {}) {
1102
1311
  const runId = readNonemptyString(event.runId);
1103
1312
  if (!runId || typeof event.state !== "string" || ![
1104
1313
  "delta",
@@ -1112,6 +1321,7 @@ function reduceSessionProjectionRunEventImpl(projection, event, scope = {}) {
1112
1321
  const errorKind = readNonemptyString(event.errorKind);
1113
1322
  const base = {
1114
1323
  runId,
1324
+ seq: typeof event.seq === "number" ? event.seq : void 0,
1115
1325
  ...message === void 0 ? {} : { message },
1116
1326
  scope
1117
1327
  };
@@ -1135,8 +1345,6 @@ function reduceSessionProjectionRunEventImpl(projection, event, scope = {}) {
1135
1345
  //#endregion
1136
1346
  //#region packages/gateway-client/src/session-projection.ts
1137
1347
  /** Browser-safe identity and replay rules shared by Gateway conversation clients. */
1138
- const MAX_TRACKED_SESSION_RUNS = 200;
1139
- const RETAINED_SESSION_RUNS = 150;
1140
1348
  const SESSION_PROJECTION_SCOPE_KEYS = [
1141
1349
  "sessionKey",
1142
1350
  "sessionId",
@@ -1290,12 +1498,39 @@ function reconcileSessionProjectionSnapshot(state, messages, scope = {}, options
1290
1498
  const visibleMessages = options.shouldIncludeMessage ? messages.filter(options.shouldIncludeMessage) : messages;
1291
1499
  if (!scopesMatch(state.scope, scope)) return createSessionProjection(scope, visibleMessages);
1292
1500
  let entries = createProjectionEntries(visibleMessages);
1501
+ const runs = { ...state.runs };
1293
1502
  for (const current of state.entries) {
1294
- if (!current.live && !current.pending || options.shouldIncludeMessage?.(current.message) === false || entries.filter((entry) => entryMatches(entry, current, true)).length === 1) continue;
1295
- entries = insertEntry(entries, current, state.runs);
1503
+ if (!current.live && !current.pending || options.shouldIncludeMessage?.(current.message) === false) continue;
1504
+ const matches = entries.filter((entry) => entryMatches(entry, current, true));
1505
+ const run = current.identity?.runId ? runs[current.identity.runId] : void 0;
1506
+ const terminalMatch = findUniqueSnapshotTerminalMatch(current, matches, run, entries);
1507
+ if (matches.length === 1 && !isUnsequencedLiveTerminal(current, run) || terminalMatch) {
1508
+ if (terminalMatch?.inferred && terminalMatch.entry.identity && current.identity?.runId && run) runs[current.identity.runId] = {
1509
+ ...run,
1510
+ inferredSnapshotTerminal: {
1511
+ entry: current,
1512
+ matchedIdentity: terminalMatch.entry.identity
1513
+ }
1514
+ };
1515
+ continue;
1516
+ }
1517
+ entries = insertEntry(entries, current, runs);
1518
+ }
1519
+ for (const [runId, run] of Object.entries(runs)) {
1520
+ const inferred = run.inferredSnapshotTerminal;
1521
+ if (!inferred) continue;
1522
+ const candidateRemains = entries.some((entry) => sameTranscriptIdentity(entry.identity, inferred.matchedIdentity));
1523
+ const visible = options.shouldIncludeMessage?.(inferred.entry.message) !== false;
1524
+ const matches = entries.filter((entry) => entryMatches(entry, inferred.entry, true));
1525
+ const terminalMatch = findUniqueSnapshotTerminalMatch(inferred.entry, matches, run, entries);
1526
+ if (candidateRemains && visible && terminalMatch?.inferred) continue;
1527
+ if (candidateRemains && visible && !terminalMatch) entries = insertEntry(entries, inferred.entry, runs);
1528
+ const { inferredSnapshotTerminal: _inferred, ...settledRun } = run;
1529
+ runs[runId] = settledRun;
1296
1530
  }
1297
1531
  return {
1298
1532
  ...withEntries(state, entries),
1533
+ runs,
1299
1534
  scope: {
1300
1535
  ...state.scope,
1301
1536
  ...scope
@@ -1303,68 +1538,27 @@ function reconcileSessionProjectionSnapshot(state, messages, scope = {}, options
1303
1538
  hasTransportGap: false
1304
1539
  };
1305
1540
  }
1306
- function hasDisplayableSessionMessage(message) {
1307
- if (typeof message === "string") return message.trim().length > 0;
1308
- const record = asNullableRecord(message);
1309
- if (!record) return false;
1310
- const displayableBlocks = Array.isArray(record.content) && record.content.some((block) => {
1311
- const entry = asNullableRecord(block);
1312
- return entry ? entry.type !== "text" || readSessionProjectionString(entry.text) !== null : typeof block === "string" && block.trim().length > 0;
1313
- });
1314
- const media = asNullableRecord(record["__openclaw"])?.media;
1315
- return Boolean(typeof record.content === "string" && record.content.trim() || displayableBlocks || Array.isArray(media) && media.length > 0);
1316
- }
1317
- function readSessionProjectionFinalMessageIdentity(message) {
1318
- if (!hasDisplayableSessionMessage(message)) return null;
1319
- const identity = readSessionMessageIdentity(message);
1320
- if (identity?.externalSource) return `import:${identity.role}:${identity.externalSource}`;
1321
- if (identity?.id && !identity.isImported) return `id:${identity.role}:${identity.id}`;
1322
- if (identity?.sequence !== null && identity?.sequence !== void 0) return `seq:${identity.role}:${identity.sequence}`;
1323
- const record = asNullableRecord(message);
1324
- const metadata = asNullableRecord(record?.["__openclaw"]);
1325
- try {
1326
- return `content:${JSON.stringify([
1327
- identity?.role ?? "assistant",
1328
- typeof message === "string" ? message : record?.content ?? null,
1329
- metadata?.media ?? null,
1330
- identity?.isImported ? [
1331
- metadata?.importedFrom ?? null,
1332
- metadata?.cliSessionId ?? null,
1333
- metadata?.externalId ?? null
1334
- ] : null
1335
- ])}`;
1336
- } catch {
1337
- return null;
1338
- }
1339
- }
1340
- /** Replayed finals are recognized against this run's bounded canonical terminal history. */
1341
- function hasSessionProjectionAcceptedFinal(run, message) {
1342
- const identity = readSessionProjectionFinalMessageIdentity(message);
1343
- return Boolean(identity && run && (run.acceptedFinalMessageIdentities?.includes(identity) || readSessionProjectionFinalMessageIdentity(run.message) === identity));
1344
- }
1345
- function retainSessionProjectionRuns(runs) {
1346
- const entries = Object.entries(runs);
1347
- if (entries.length <= MAX_TRACKED_SESSION_RUNS) return runs;
1348
- const active = entries.filter(([, run]) => run.status === "streaming");
1349
- const terminal = entries.filter(([, run]) => run.status !== "streaming");
1350
- const terminalLimit = Math.max(0, RETAINED_SESSION_RUNS - active.length);
1351
- const retainedTerminal = terminalLimit > 0 ? terminal.slice(-terminalLimit) : [];
1352
- return Object.fromEntries([...active, ...retainedTerminal]);
1353
- }
1354
1541
  function updateRun(state, incoming) {
1355
1542
  const incomingErrorMessage = readSessionProjectionString(incoming.errorMessage);
1356
- const normalizedIncoming = { ...incoming };
1543
+ const incomingSeq = typeof incoming.seq === "number" && Number.isSafeInteger(incoming.seq) && incoming.seq >= 0 ? incoming.seq : void 0;
1544
+ const normalizedIncoming = {
1545
+ ...incoming,
1546
+ seq: incomingSeq
1547
+ };
1357
1548
  if (incomingErrorMessage) normalizedIncoming.errorMessage = incomingErrorMessage;
1358
1549
  else delete normalizedIncoming.errorMessage;
1359
1550
  const current = state.runs[incoming.runId];
1360
- if (current && current.status !== "streaming") {
1551
+ const resumesErrorProjection = current?.status === "error" && incoming.status === "streaming" && current.seq !== void 0 && incomingSeq !== void 0 && incomingSeq > current.seq && isSessionProjectionErrorMessage(current.message, current.errorMessage);
1552
+ if (current && current.status !== "streaming" && !resumesErrorProjection) {
1361
1553
  const incomingFinalIdentity = readSessionProjectionFinalMessageIdentity(incoming.message);
1362
1554
  const incomingIsFinal = incoming.status === "completed" || incoming.status === "yielded";
1363
- const canRecoverFinal = !hasDisplayableSessionMessage(current.message) || (current.acceptedFinalMessageIdentities?.length ?? 0) > 0;
1364
- const acceptFinal = incomingIsFinal && (current.status === incoming.status || canRecoverFinal) && incomingFinalIdentity !== null && !hasSessionProjectionAcceptedFinal(current, incoming.message);
1365
- const recoverMessage = acceptFinal && !hasDisplayableSessionMessage(current.message);
1555
+ const currentHasDisplayableMessage = hasDisplayableSessionMessage(current.message);
1556
+ const canAcceptFinal = currentHasDisplayableMessage ? current.status === incoming.status || (current.acceptedFinalMessageIdentities?.length ?? 0) > 0 : canRecoverSessionProjectionFinal(current.message, incoming.message);
1557
+ const acceptFinal = incomingIsFinal && canAcceptFinal && incomingFinalIdentity !== null && !hasSessionProjectionAcceptedFinal(current, incoming.message);
1558
+ const recoverMessage = acceptFinal && !currentHasDisplayableMessage;
1366
1559
  const recoverError = readSessionProjectionString(current.errorMessage) === null && incomingErrorMessage !== null;
1367
- if (!acceptFinal && !recoverError) return state;
1560
+ const updateTerminalSequence = incoming.status !== "streaming" && (incomingSeq === void 0 ? current.seq !== void 0 : current.seq === void 0 || incomingSeq > current.seq);
1561
+ if (!acceptFinal && !recoverError && !updateTerminalSequence) return state;
1368
1562
  const firstFinalIdentity = readSessionProjectionFinalMessageIdentity(current.message);
1369
1563
  const previousFinalIdentities = current.acceptedFinalMessageIdentities ?? (firstFinalIdentity ? [firstFinalIdentity] : []);
1370
1564
  return {
@@ -1373,6 +1567,7 @@ function updateRun(state, incoming) {
1373
1567
  ...state.runs,
1374
1568
  [incoming.runId]: {
1375
1569
  ...current,
1570
+ ...updateTerminalSequence ? { seq: incomingSeq } : {},
1376
1571
  ...recoverMessage ? { message: incoming.message } : {},
1377
1572
  ...acceptFinal && incomingFinalIdentity ? { acceptedFinalMessageIdentities: [...previousFinalIdentities, incomingFinalIdentity].slice(-32) } : {},
1378
1573
  ...recoverError && incomingErrorMessage ? {
@@ -1383,17 +1578,18 @@ function updateRun(state, incoming) {
1383
1578
  }
1384
1579
  };
1385
1580
  }
1581
+ const resumedState = resumesErrorProjection ? withEntries(state, state.entries.filter((entry) => !((entry.identity?.runId === incoming.runId || entry.message === current.message) && (asNullableRecord(entry.message)?.stopReason === "error" || entry.message === current.message) && isSessionProjectionErrorMessage(entry.message, current.errorMessage)))) : state;
1386
1582
  const previousRuns = current && current.status === "streaming" && incoming.status !== "streaming" ? Object.fromEntries(Object.entries(state.runs).filter(([runId]) => runId !== incoming.runId)) : state.runs;
1387
1583
  const acceptedFinalIdentity = incoming.status === "completed" || incoming.status === "yielded" ? readSessionProjectionFinalMessageIdentity(incoming.message) : null;
1388
1584
  return {
1389
- ...state,
1585
+ ...resumedState,
1390
1586
  runs: retainSessionProjectionRuns({
1391
1587
  ...previousRuns,
1392
1588
  [incoming.runId]: {
1393
- ...current,
1589
+ ...resumesErrorProjection ? {} : current,
1394
1590
  ...normalizedIncoming,
1395
1591
  ...acceptedFinalIdentity ? { acceptedFinalMessageIdentities: [acceptedFinalIdentity] } : {},
1396
- ...incoming.message === void 0 && current?.message !== void 0 ? { message: current.message } : {}
1592
+ ...!resumesErrorProjection && incoming.message === void 0 && current?.message !== void 0 ? { message: current.message } : {}
1397
1593
  }
1398
1594
  })
1399
1595
  };
@@ -1451,11 +1647,13 @@ function reduceSessionProjection(state, event) {
1451
1647
  }
1452
1648
  case "runDelta": return updateRun(state, {
1453
1649
  runId: event.runId,
1650
+ seq: event.seq,
1454
1651
  status: "streaming",
1455
1652
  ...event.message === void 0 ? {} : { message: event.message }
1456
1653
  });
1457
1654
  case "runTerminal": return updateRun(state, {
1458
1655
  runId: event.runId,
1656
+ seq: event.seq,
1459
1657
  status: event.status,
1460
1658
  ...event.message === void 0 ? {} : { message: event.message },
1461
1659
  ...event.stopReason === void 0 ? {} : { stopReason: event.stopReason },
@@ -1470,10 +1668,6 @@ function reduceSessionProjection(state, event) {
1470
1668
  default: return state;
1471
1669
  }
1472
1670
  }
1473
- /** Normalizes Gateway run envelopes once for every browser and terminal adapter. */
1474
- function reduceSessionProjectionRunEvent(projection, event, scope = {}) {
1475
- return reduceSessionProjectionRunEventImpl(projection, event, scope);
1476
- }
1477
1671
  //#endregion
1478
1672
  //#region packages/gateway-client/src/session-subscriptions.ts
1479
1673
  function sessionSubscriptionParams(key, agentId) {
@@ -1591,34 +1785,26 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
1591
1785
  agentId,
1592
1786
  ready: Promise.resolve({ key }),
1593
1787
  approvalRequest: null,
1594
- approvalResponse: null,
1595
1788
  plainFallback: null,
1596
1789
  canonicalSettled: false,
1597
1790
  handles: /* @__PURE__ */ new Set(),
1598
1791
  pendingOwners: 0,
1599
1792
  release: null
1600
1793
  };
1601
- entry.ready = this.#requestSubscribe(entry, includeApprovals).then((result) => {
1602
- entry.key = result.key;
1603
- entry.canonicalSettled = true;
1604
- if (includeApprovals) entry.approvalResponse = result;
1605
- return result;
1606
- });
1607
- if (includeApprovals) entry.approvalRequest = entry.ready;
1794
+ entry.ready = this.#requestSubscribe(entry, includeApprovals);
1795
+ if (includeApprovals) entry.ready = this.#trackApprovalRequest(entry, entry.ready);
1608
1796
  entry.ready.catch(() => void 0);
1609
1797
  this.#entries.add(entry);
1610
1798
  return entry;
1611
1799
  }
1612
1800
  #acquireCapability(entry, includeApprovals) {
1613
1801
  if (!includeApprovals) {
1614
- if (entry.approvalRequest === entry.ready && !entry.approvalResponse) {
1802
+ if (entry.approvalRequest === entry.ready) {
1615
1803
  if (!entry.plainFallback) {
1616
1804
  const approvalRequest = entry.ready;
1617
1805
  entry.plainFallback = approvalRequest.catch(async (error) => {
1618
1806
  if (this.#retired) throw error;
1619
1807
  const result = await this.#requestSubscribe(entry, false);
1620
- entry.key = result.key;
1621
- entry.canonicalSettled = true;
1622
1808
  entry.ready = Promise.resolve(result);
1623
1809
  if (entry.approvalRequest === approvalRequest) entry.approvalRequest = null;
1624
1810
  return result;
@@ -1628,18 +1814,15 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
1628
1814
  }
1629
1815
  return entry.ready;
1630
1816
  }
1631
- if (entry.approvalResponse) return Promise.resolve(entry.approvalResponse);
1632
1817
  if (entry.approvalRequest) return entry.approvalRequest;
1633
- const upgrade = entry.ready.then(() => this.#requestSubscribe(entry, true)).then((result) => {
1634
- entry.key = result.key;
1635
- entry.approvalResponse = result;
1636
- return result;
1637
- });
1638
- entry.approvalRequest = upgrade;
1639
- upgrade.catch(() => {
1640
- if (entry.approvalRequest === upgrade) entry.approvalRequest = null;
1818
+ return this.#trackApprovalRequest(entry, entry.ready.then(() => this.#requestSubscribe(entry, true)));
1819
+ }
1820
+ #trackApprovalRequest(entry, request) {
1821
+ const tracked = request.finally(() => {
1822
+ if (entry.approvalRequest === tracked) entry.approvalRequest = null;
1641
1823
  });
1642
- return upgrade;
1824
+ entry.approvalRequest = tracked;
1825
+ return tracked;
1643
1826
  }
1644
1827
  async #requestSubscribe(entry, includeApprovals) {
1645
1828
  const params = sessionSubscriptionParams(entry.key, entry.agentId);
@@ -1649,7 +1832,11 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
1649
1832
  } : params, { timeoutMs: DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS }).catch(async (error) => {
1650
1833
  if (!(error instanceof GatewayProtocolRequestTimeoutError) || !error.requestSent || this.#retired) throw error;
1651
1834
  try {
1652
- await this.#client.request(entry.handles.size > 0 ? "sessions.messages.subscribe" : "sessions.messages.unsubscribe", params, { timeoutMs: DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS });
1835
+ const retainedApprovals = [...entry.handles].some((handle) => handle.includeApprovals);
1836
+ await this.#client.request(entry.handles.size > 0 ? "sessions.messages.subscribe" : "sessions.messages.unsubscribe", retainedApprovals ? {
1837
+ ...params,
1838
+ includeApprovals: true
1839
+ } : params, { timeoutMs: DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS });
1653
1840
  } catch (recoveryError) {
1654
1841
  if (!this.#retired) throw new AggregateError([error, recoveryError], "session message subscription recovery failed", { cause: recoveryError });
1655
1842
  }
@@ -1657,8 +1844,10 @@ var GatewaySessionMessageSubscriptionCoordinator = class {
1657
1844
  });
1658
1845
  const response = result && typeof result === "object" ? result : null;
1659
1846
  const responseKey = response && "key" in response ? response.key : void 0;
1847
+ entry.key = typeof responseKey === "string" && responseKey.trim() ? responseKey.trim() : entry.key;
1848
+ entry.canonicalSettled = true;
1660
1849
  return {
1661
- key: typeof responseKey === "string" && responseKey.trim() ? responseKey.trim() : entry.key,
1850
+ key: entry.key,
1662
1851
  ...response && "approvalReplay" in response ? { approvalReplay: response.approvalReplay } : {}
1663
1852
  };
1664
1853
  }
@@ -1694,4 +1883,4 @@ function releaseGatewaySessionMessageSubscription(subscription) {
1694
1883
  return sessionMessageSubscriptionOwners.get(subscription)?.coordinator.release(subscription) ?? Promise.resolve();
1695
1884
  }
1696
1885
  //#endregion
1697
- export { buildDeviceAuthPayloadV3 as A, gatewayOriginScope as C, selectGatewayConnectAuth as D, resolveGatewayConnectScopes as E, shouldRetryGatewayWithDeviceToken as O, gatewayCredentialScope as S, buildGatewayConnectAuth as T, shouldPauseGatewayReconnect as _, createSessionProjection as a, GatewayProtocolRequestTimeoutError as b, projectLiveSessionMessage as c, reduceSessionProjectionRunEvent as d, normalizeSessionProjectionRunId as f, isRecord as g, readSessionMessageSequence as h, resetGatewaySessionMessageSubscriptionCoordinator as i, normalizeDeviceMetadataForAuth as j, buildDeviceAuthPayload as k, reconcileSessionProjectionSnapshot as l, readSessionMessageIdentity as m, getGatewaySessionMessageSubscriptionCoordinator as n, hasSessionProjectionAcceptedFinal as o, readAssistantStreamSegmentIdentity as p, releaseGatewaySessionMessageSubscription as r, isLocallyOptimisticSessionMessage as s, GatewaySessionMessageSubscriptionCoordinator as t, reduceSessionProjection as u, GatewayProtocolClient as v, GatewayBrowserDeviceAuthLifecycle as w, isGatewayProtocolResponseError as x, GatewayProtocolRequestError as y };
1886
+ export { shouldRetryGatewayWithDeviceToken as A, isGatewayProtocolResponseError as C, buildGatewayConnectAuth as D, GatewayBrowserDeviceAuthLifecycle as E, buildDeviceAuthPayloadV3 as M, normalizeDeviceMetadataForAuth as N, resolveGatewayConnectScopes as O, GatewayProtocolRequestTimeoutError as S, gatewayOriginScope as T, readSessionMessageSequence as _, createSessionProjection as a, GatewayProtocolClient as b, reconcileSessionProjectionSnapshot as c, hasSessionProjectionAcceptedFinal as d, readSessionProjectionFinalMessageIdentity as f, readSessionMessageIdentity as g, readAssistantStreamSegmentIdentity as h, resetGatewaySessionMessageSubscriptionCoordinator as i, buildDeviceAuthPayload as j, selectGatewayConnectAuth as k, reduceSessionProjection as l, normalizeSessionProjectionRunId as m, getGatewaySessionMessageSubscriptionCoordinator as n, isLocallyOptimisticSessionMessage as o, isSessionProjectionErrorMessage as p, releaseGatewaySessionMessageSubscription as r, projectLiveSessionMessage as s, GatewaySessionMessageSubscriptionCoordinator as t, reduceSessionProjectionRunEvent as u, isRecord as v, gatewayCredentialScope as w, GatewayProtocolRequestError as x, shouldPauseGatewayReconnect as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/gateway-client",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.4",
4
4
  "description": "Reference WebSocket client for the OpenClaw Gateway protocol",
5
5
  "keywords": [
6
6
  "client",
@@ -62,7 +62,7 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@openclaw/gateway-protocol": "2026.9.2",
65
+ "@openclaw/gateway-protocol": "2026.9.4",
66
66
  "ipaddr.js": "2.5.0",
67
67
  "ws": "8.21.3"
68
68
  },