@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.
- package/dist/browser.d.mts +3 -3
- package/dist/browser.mjs +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +13 -3
- package/dist/{readiness-uQKoJkl5.d.mts → readiness-DabX0O0A.d.mts} +3 -0
- package/dist/readiness.d.mts +1 -1
- package/dist/{session-subscriptions-D2UdeJ0u.d.mts → session-subscriptions-BSQIANvX.d.mts} +36 -14
- package/dist/{session-subscriptions-C0VxZerW.mjs → session-subscriptions-DIcpqS8A.mjs} +288 -99
- package/package.json +2 -2
package/dist/browser.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { A as
|
|
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
|
|
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
|
|
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-
|
|
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
|
|
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[];
|
package/dist/readiness.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as startGatewayClientWithReadinessWait, i as startGatewayClientWhenEventLoopReady, n as GatewayClientStartReadinessOptions, r as GatewayClientStartable, t as EventLoopReadyWaiter } from "./readiness-
|
|
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 {
|
|
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
|
-
|
|
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 =
|
|
582
|
-
this.pending
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1295
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1364
|
-
const
|
|
1365
|
-
const
|
|
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
|
-
|
|
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
|
-
...
|
|
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
|
-
|
|
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)
|
|
1602
|
-
|
|
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
|
|
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
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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 {
|
|
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.
|
|
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.
|
|
65
|
+
"@openclaw/gateway-protocol": "2026.9.4",
|
|
66
66
|
"ipaddr.js": "2.5.0",
|
|
67
67
|
"ws": "8.21.3"
|
|
68
68
|
},
|