@openclaw/gateway-protocol 2026.7.2-beta.7 → 2026.8.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,10 +7,13 @@ version and the additive schema surface. Dates are authoring dates (2026).
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ - Add bounded `sessions.patchMany` session mutation orchestration.
11
+ - Preserve required legacy agent-default fields while adding honest `ownership` and `selectionRequired` state to agent lists and initial snapshots.
10
12
  - Add semantic `agent` / `system` roster kinds negotiated through the `agent-kind` client capability.
11
13
  - Rename structured-question item `id` to `questionId` and flatten keyed answer arrays.
12
14
  - Slim worker and session-catalog payloads to the active wire contract.
13
15
  - Remove dead protocol surfaces and add since-vintage metadata to retained schemas and methods.
16
+ - Add optional `step` on `SystemAgentChatResult` carrying the full awaited wizard step.
14
17
 
15
18
  ## Protocol v4 (current)
16
19
 
@@ -126,7 +129,8 @@ Enhancement-only month (no new schema modules):
126
129
  - Add cron event triggers via polled condition-watcher scripts (#101195) and native
127
130
  mobile Automations parity (#106355).
128
131
  - Add system-agent conversational onboarding (#99935); rename `crestodian.*` methods to
129
- `openclaw.chat` / `openclaw.setup.*` (2026-07-14, `a6a0716`).
132
+ `openclaw.chat` / `openclaw.setup.*` (2026-07-14, `a6a0716`); add typed hosted-wizard
133
+ steps and answers to `openclaw.chat` (#114631).
130
134
  - Add typed structured questions / `ask_user` with live option cards (#109922, #110242)
131
135
  and the questions schema module.
132
136
  - Add ui-command / screen-tool Control UI layout control and capability-gated
package/README.md CHANGED
@@ -128,7 +128,7 @@ Several identifier names coexist because they identify different things:
128
128
 
129
129
  Follow each method schema rather than converting fields based on their spelling.
130
130
  `sessions.resolve` is the explicit bridge when a caller has a key, raw session ID,
131
- label, or parent/agent scope.
131
+ label, Control UI short ID, or parent/agent scope.
132
132
 
133
133
  ### Intentionally open fields
134
134
 
@@ -59,7 +59,8 @@ type GatewayClientMode = (typeof GATEWAY_CLIENT_MODES)[keyof typeof GATEWAY_CLIE
59
59
  type GatewayClientInfo = {
60
60
  /** Stable product/client identifier from `GATEWAY_CLIENT_IDS`. */id: GatewayClientId; /** Human-readable label for diagnostics; not used for policy decisions. */
61
61
  displayName?: string; /** Client app or package version reported by the connecting process. */
62
- version: string; /** Runtime platform string, such as `darwin`, `ios`, `android`, or `web`. */
62
+ version: string; /** Exact immutable artifact identity when the client can report one. */
63
+ buildId?: string; /** Runtime platform string, such as `darwin`, `ios`, `android`, or `web`. */
63
64
  platform: string; /** Optional device family used by native clients for display and routing hints. */
64
65
  deviceFamily?: string; /** Native hardware/model identifier when available. */
65
66
  modelIdentifier?: string; /** Coarse category from `GATEWAY_CLIENT_MODES` for policy and diagnostics. */
@@ -1,3 +1,4 @@
1
+ import { i as normalizeOptionalProtocolString } from "./protocol-value-normalization-Bexl3yr1.mjs";
1
2
  //#region src/client-info.ts
2
3
  /**
3
4
  * Shared gateway client identity contract.
@@ -5,9 +6,8 @@
5
6
  * These values cross the WebSocket handshake boundary, so additions must stay
6
7
  * aligned with protocol schemas and server policy checks.
7
8
  */
8
- function normalizeOptionalLowercaseString(raw) {
9
- if (typeof raw !== "string") return;
10
- return raw.trim().toLowerCase() || void 0;
9
+ function normalizeOptionalProtocolLowercaseString(raw) {
10
+ return normalizeOptionalProtocolString(raw)?.toLowerCase();
11
11
  }
12
12
  /** Canonical client ids accepted in gateway hello/connect payloads. */
13
13
  const GATEWAY_CLIENT_IDS = {
@@ -59,7 +59,7 @@ const GATEWAY_CLIENT_ID_SET = new Set(Object.values(GATEWAY_CLIENT_IDS));
59
59
  const GATEWAY_CLIENT_MODE_SET = new Set(Object.values(GATEWAY_CLIENT_MODES));
60
60
  /** Normalizes untrusted client ids and rejects unknown values. */
61
61
  function normalizeGatewayClientId(raw) {
62
- const normalized = normalizeOptionalLowercaseString(raw);
62
+ const normalized = normalizeOptionalProtocolLowercaseString(raw);
63
63
  if (!normalized) return;
64
64
  return GATEWAY_CLIENT_ID_SET.has(normalized) ? normalized : void 0;
65
65
  }
@@ -69,7 +69,7 @@ function normalizeGatewayClientName(raw) {
69
69
  }
70
70
  /** Normalizes untrusted client modes and rejects unknown values. */
71
71
  function normalizeGatewayClientMode(raw) {
72
- const normalized = normalizeOptionalLowercaseString(raw);
72
+ const normalized = normalizeOptionalProtocolLowercaseString(raw);
73
73
  if (!normalized) return;
74
74
  return GATEWAY_CLIENT_MODE_SET.has(normalized) ? normalized : void 0;
75
75
  }
@@ -17,6 +17,7 @@ declare const ConnectErrorDetailCodes: {
17
17
  readonly AUTH_TAILSCALE_PROXY_MISSING: "AUTH_TAILSCALE_PROXY_MISSING";
18
18
  readonly AUTH_TAILSCALE_WHOIS_FAILED: "AUTH_TAILSCALE_WHOIS_FAILED";
19
19
  readonly AUTH_TAILSCALE_IDENTITY_MISMATCH: "AUTH_TAILSCALE_IDENTITY_MISMATCH";
20
+ readonly CONTROL_UI_BUILD_MISMATCH: "CONTROL_UI_BUILD_MISMATCH";
20
21
  readonly CONTROL_UI_ORIGIN_NOT_ALLOWED: "CONTROL_UI_ORIGIN_NOT_ALLOWED";
21
22
  readonly PROTOCOL_MISMATCH: "PROTOCOL_MISMATCH";
22
23
  readonly CONTROL_UI_DEVICE_IDENTITY_REQUIRED: "CONTROL_UI_DEVICE_IDENTITY_REQUIRED";
@@ -70,6 +71,8 @@ declare function resolveAuthConnectErrorDetailCode(reason: string | undefined):
70
71
  declare function resolveDeviceAuthConnectErrorDetailCode(reason: string | undefined): ConnectErrorDetailCode;
71
72
  /** Reads a non-empty detail code from an untrusted error details payload. */
72
73
  declare function readConnectErrorDetailCode(details: unknown): string | null;
74
+ /** Read the exact target artifact from an untrusted reload-required rejection. */
75
+ declare function readControlUiBuildMismatchId(details: unknown): string | null;
73
76
  /** Extracts normalized retry advice from untrusted connect-error details. */
74
77
  declare function readConnectErrorRecoveryAdvice(details: unknown): ConnectErrorRecoveryAdvice;
75
78
  /** Normalizes pairing request ids before echoing them in close reasons or UI text. */
@@ -103,6 +106,20 @@ declare function buildPairingConnectCloseReason(params: {
103
106
  declare function readPairingConnectErrorDetails(details: unknown): PairingConnectErrorDetails | null;
104
107
  /** Parses legacy/string-only pairing-required messages into structured details. */
105
108
  declare function readConnectPairingRequiredMessage(message: string | null | undefined): ConnectPairingRequiredDetails | null;
109
+ /** Classifies Gateway connect failures from structured details, with one legacy text fallback. */
110
+ declare function classifyGatewayConnectFailure(input: {
111
+ details?: unknown;
112
+ reason?: string | null;
113
+ message?: string | null;
114
+ }): {
115
+ kind: "pairing-required";
116
+ userMessage: string;
117
+ remediation: string;
118
+ } | {
119
+ remediation?: string | undefined;
120
+ kind: "device-identity-required" | "scope-mismatch" | "rate-limited" | "auth-rejected" | "gateway-rejected" | "unreachable";
121
+ userMessage: string;
122
+ };
106
123
  /** Formats pairing-required details into the canonical user-facing message. */
107
124
  declare function formatConnectPairingRequiredMessage(details: unknown): string;
108
125
  /** Formats connect errors using structured details before falling back to raw messages. */
@@ -111,4 +128,4 @@ declare function formatConnectErrorMessage(params: {
111
128
  details?: unknown;
112
129
  }): string;
113
130
  //#endregion
114
- export { ConnectErrorDetailCodes, ConnectPairingRequiredDetails, ConnectPairingRequiredReason, buildPairingConnectCloseReason, buildPairingConnectErrorDetails, buildPairingConnectErrorMessage, buildPairingConnectRecoveryTitle, describePairingConnectRequirement, formatConnectErrorMessage, formatConnectPairingRequiredMessage, normalizePairingConnectRequestId, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readConnectPairingRequiredMessage, readPairingConnectErrorDetails, resolveAuthConnectErrorDetailCode, resolveDeviceAuthConnectErrorDetailCode };
131
+ export { ConnectErrorDetailCodes, ConnectPairingRequiredDetails, ConnectPairingRequiredReason, buildPairingConnectCloseReason, buildPairingConnectErrorDetails, buildPairingConnectErrorMessage, buildPairingConnectRecoveryTitle, classifyGatewayConnectFailure, describePairingConnectRequirement, formatConnectErrorMessage, formatConnectPairingRequiredMessage, normalizePairingConnectRequestId, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readConnectPairingRequiredMessage, readControlUiBuildMismatchId, readPairingConnectErrorDetails, resolveAuthConnectErrorDetailCode, resolveDeviceAuthConnectErrorDetailCode };
@@ -1,3 +1,4 @@
1
+ import { i as normalizeOptionalProtocolString } from "./protocol-value-normalization-Bexl3yr1.mjs";
1
2
  //#region src/connect-error-details.ts
2
3
  /**
3
4
  * Shared gateway connect-error detail helpers.
@@ -5,13 +6,9 @@
5
6
  * These details cross client/server boundaries, so readers normalize untrusted
6
7
  * payloads before using them in reconnect decisions or user-facing messages.
7
8
  */
8
- function normalizeOptionalString(value) {
9
- if (typeof value !== "string") return;
10
- return value.trim() || void 0;
11
- }
12
- function normalizeArrayBackedTrimmedStringList(value) {
9
+ function normalizeOptionalConnectDetailStringList(value) {
13
10
  if (!Array.isArray(value)) return;
14
- const values = value.map((entry) => normalizeOptionalString(entry)).filter((entry) => Boolean(entry));
11
+ const values = value.map((entry) => normalizeOptionalProtocolString(entry)).filter((entry) => Boolean(entry));
15
12
  return values.length > 0 ? values : void 0;
16
13
  }
17
14
  /** Structured connect-error codes carried in gateway error `details.code`. */
@@ -32,6 +29,7 @@ const ConnectErrorDetailCodes = {
32
29
  AUTH_TAILSCALE_PROXY_MISSING: "AUTH_TAILSCALE_PROXY_MISSING",
33
30
  AUTH_TAILSCALE_WHOIS_FAILED: "AUTH_TAILSCALE_WHOIS_FAILED",
34
31
  AUTH_TAILSCALE_IDENTITY_MISMATCH: "AUTH_TAILSCALE_IDENTITY_MISMATCH",
32
+ CONTROL_UI_BUILD_MISMATCH: "CONTROL_UI_BUILD_MISMATCH",
35
33
  CONTROL_UI_ORIGIN_NOT_ALLOWED: "CONTROL_UI_ORIGIN_NOT_ALLOWED",
36
34
  PROTOCOL_MISMATCH: "PROTOCOL_MISMATCH",
37
35
  CONTROL_UI_DEVICE_IDENTITY_REQUIRED: "CONTROL_UI_DEVICE_IDENTITY_REQUIRED",
@@ -134,28 +132,36 @@ function readConnectErrorDetailCode(details) {
134
132
  const code = details.code;
135
133
  return typeof code === "string" && code.trim().length > 0 ? code.trim() : null;
136
134
  }
135
+ /** Read the exact target artifact from an untrusted reload-required rejection. */
136
+ function readControlUiBuildMismatchId(details) {
137
+ if (readConnectErrorDetailCode(details) !== ConnectErrorDetailCodes.CONTROL_UI_BUILD_MISMATCH) return null;
138
+ const raw = details;
139
+ const gatewayBuildId = normalizeOptionalProtocolString(raw.gatewayBuildId);
140
+ if (!gatewayBuildId || gatewayBuildId.length > 96 || raw.reloadRequired !== true) return null;
141
+ return gatewayBuildId;
142
+ }
137
143
  /** Extracts normalized retry advice from untrusted connect-error details. */
138
144
  function readConnectErrorRecoveryAdvice(details) {
139
145
  if (!details || typeof details !== "object" || Array.isArray(details)) return {};
140
146
  const raw = details;
141
147
  const canRetryWithDeviceToken = typeof raw.canRetryWithDeviceToken === "boolean" ? raw.canRetryWithDeviceToken : void 0;
142
- const normalizedNextStep = normalizeOptionalString(raw.recommendedNextStep) ?? "";
148
+ const normalizedNextStep = normalizeOptionalProtocolString(raw.recommendedNextStep) ?? "";
143
149
  return {
144
150
  canRetryWithDeviceToken,
145
151
  recommendedNextStep: CONNECT_RECOVERY_NEXT_STEP_VALUES.has(normalizedNextStep) ? normalizedNextStep : void 0
146
152
  };
147
153
  }
148
154
  function normalizePairingConnectReason(value) {
149
- const normalized = normalizeOptionalString(value) ?? "";
155
+ const normalized = normalizeOptionalProtocolString(value) ?? "";
150
156
  return CONNECT_PAIRING_REQUIRED_REASON_VALUES.has(normalized) ? normalized : void 0;
151
157
  }
152
158
  /** Normalizes pairing request ids before echoing them in close reasons or UI text. */
153
159
  function normalizePairingConnectRequestId(value) {
154
- const normalized = normalizeOptionalString(value);
160
+ const normalized = normalizeOptionalProtocolString(value);
155
161
  return normalized && PAIRING_CONNECT_REQUEST_ID_PATTERN.test(normalized) ? normalized : void 0;
156
162
  }
157
163
  function normalizeStringArray(value) {
158
- return normalizeArrayBackedTrimmedStringList(value);
164
+ return normalizeOptionalConnectDetailStringList(value);
159
165
  }
160
166
  function createPairingConnectErrorDetails(params) {
161
167
  return {
@@ -191,9 +197,9 @@ function buildPairingConnectRecoveryTitle(reason) {
191
197
  /** Builds sanitized structured details for a pairing-required connect failure. */
192
198
  function buildPairingConnectErrorDetails(params) {
193
199
  const requestId = normalizePairingConnectRequestId(params.requestId);
194
- const remediationHint = normalizeOptionalString(params.remediationHint) ?? buildPairingConnectRemediationHint(params.reason);
195
- const deviceId = normalizeOptionalString(params.deviceId);
196
- const requestedRole = normalizeOptionalString(params.requestedRole);
200
+ const remediationHint = normalizeOptionalProtocolString(params.remediationHint) ?? buildPairingConnectRemediationHint(params.reason);
201
+ const deviceId = normalizeOptionalProtocolString(params.deviceId);
202
+ const requestedRole = normalizeOptionalProtocolString(params.requestedRole);
197
203
  const requestedScopes = normalizeStringArray(params.requestedScopes);
198
204
  const approvedRoles = normalizeStringArray(params.approvedRoles);
199
205
  const approvedScopes = normalizeStringArray(params.approvedScopes);
@@ -224,11 +230,11 @@ function readPairingConnectErrorDetails(details) {
224
230
  const raw = details;
225
231
  const reason = normalizePairingConnectReason(raw.reason);
226
232
  const requestId = normalizePairingConnectRequestId(raw.requestId);
227
- const remediationHint = normalizeOptionalString(raw.remediationHint) ?? buildPairingConnectRemediationHint(reason);
228
- const normalizedNextStep = normalizeOptionalString(raw.recommendedNextStep) ?? "";
233
+ const remediationHint = normalizeOptionalProtocolString(raw.remediationHint) ?? buildPairingConnectRemediationHint(reason);
234
+ const normalizedNextStep = normalizeOptionalProtocolString(raw.recommendedNextStep) ?? "";
229
235
  const recommendedNextStep = CONNECT_RECOVERY_NEXT_STEP_VALUES.has(normalizedNextStep) ? normalizedNextStep : void 0;
230
- const deviceId = normalizeOptionalString(raw.deviceId);
231
- const requestedRole = normalizeOptionalString(raw.requestedRole);
236
+ const deviceId = normalizeOptionalProtocolString(raw.deviceId);
237
+ const requestedRole = normalizeOptionalProtocolString(raw.requestedRole);
232
238
  const requestedScopes = normalizeStringArray(raw.requestedScopes);
233
239
  const approvedRoles = normalizeStringArray(raw.approvedRoles);
234
240
  const approvedScopes = normalizeStringArray(raw.approvedScopes);
@@ -248,7 +254,7 @@ function readPairingConnectErrorDetails(details) {
248
254
  }
249
255
  /** Parses legacy/string-only pairing-required messages into structured details. */
250
256
  function readConnectPairingRequiredMessage(message) {
251
- const normalizedMessage = normalizeOptionalString(message);
257
+ const normalizedMessage = normalizeOptionalProtocolString(message);
252
258
  if (!normalizedMessage) return null;
253
259
  const normalized = normalizedMessage.trim().toLowerCase();
254
260
  let reason;
@@ -264,6 +270,40 @@ function readConnectPairingRequiredMessage(message) {
264
270
  reason
265
271
  };
266
272
  }
273
+ const PAIRING_APPROVAL_REMEDIATION = "Run `openclaw devices approve --latest` to preview the pending request, then rerun the printed `openclaw devices approve <requestId>` command and reconnect (pass the same --url and --token/--password flags if you connected with explicit credentials).";
274
+ const DEVICE_TOKEN_REMEDIATION = "Rotate the paired-device token with `openclaw devices rotate --device <deviceId> --role operator`, then reconnect.";
275
+ const SHARED_TOKEN_REMEDIATION = "Verify `gateway.remote.token` matches `gateway.auth.token`. If a paired-device token is stale, rotate it with `openclaw devices rotate --device <deviceId> --role operator`, then reconnect.";
276
+ const SCOPE_MISMATCH_REMEDIATION = "Review approved scopes with `openclaw devices list`; if an upgrade is pending, preview it with `openclaw devices approve --latest`, approve the printed request, then reconnect.";
277
+ const RATE_LIMITED_REMEDIATION = "Wait for the temporary authentication lockout to expire, then retry.";
278
+ const GATEWAY_CLOSED_MESSAGE_PATTERN = /\bgateway closed \(\d+\):/i;
279
+ /** Classifies Gateway connect failures from structured details, with one legacy text fallback. */
280
+ function classifyGatewayConnectFailure(input) {
281
+ const code = readConnectErrorDetailCode(input.details);
282
+ const message = normalizeOptionalProtocolString(input.message);
283
+ const reason = normalizeOptionalProtocolString(input.reason);
284
+ const userMessage = message ?? reason;
285
+ const classificationText = [message, reason].filter((value) => Boolean(value)).join("\n");
286
+ const normalized = classificationText.toLowerCase();
287
+ const pairing = readPairingConnectErrorDetails(input.details) ?? readConnectPairingRequiredMessage(classificationText);
288
+ if (code === ConnectErrorDetailCodes.PAIRING_REQUIRED || pairing) return {
289
+ kind: "pairing-required",
290
+ userMessage: code === ConnectErrorDetailCodes.PAIRING_REQUIRED ? formatConnectPairingRequiredMessage(input.details) : userMessage ?? "device pairing required",
291
+ remediation: PAIRING_APPROVAL_REMEDIATION
292
+ };
293
+ const deviceIdentityRequired = code === ConnectErrorDetailCodes.DEVICE_IDENTITY_REQUIRED || code === ConnectErrorDetailCodes.CONTROL_UI_DEVICE_IDENTITY_REQUIRED || normalized.includes("device identity required");
294
+ const scopeMismatch = code === ConnectErrorDetailCodes.AUTH_SCOPE_MISMATCH || normalized.includes("scope mismatch");
295
+ const rateLimited = code === ConnectErrorDetailCodes.AUTH_RATE_LIMITED || !code && normalized.includes("too many failed authentication attempts");
296
+ const deviceTokenMismatch = code === ConnectErrorDetailCodes.AUTH_DEVICE_TOKEN_MISMATCH || normalized.includes("device token mismatch");
297
+ const sharedTokenMismatch = code === ConnectErrorDetailCodes.AUTH_TOKEN_MISMATCH || normalized.includes("gateway token mismatch");
298
+ const authRejected = deviceTokenMismatch || sharedTokenMismatch || code?.startsWith("AUTH_") || code?.startsWith("DEVICE_AUTH_");
299
+ const kind = deviceIdentityRequired ? "device-identity-required" : scopeMismatch ? "scope-mismatch" : rateLimited ? "rate-limited" : authRejected ? "auth-rejected" : code || GATEWAY_CLOSED_MESSAGE_PATTERN.test(classificationText) ? "gateway-rejected" : "unreachable";
300
+ const remediation = rateLimited ? RATE_LIMITED_REMEDIATION : scopeMismatch ? SCOPE_MISMATCH_REMEDIATION : deviceTokenMismatch ? DEVICE_TOKEN_REMEDIATION : sharedTokenMismatch ? SHARED_TOKEN_REMEDIATION : void 0;
301
+ return {
302
+ kind,
303
+ userMessage: userMessage ?? (kind === "unreachable" ? "gateway unreachable" : "gateway rejected connection"),
304
+ ...remediation ? { remediation } : {}
305
+ };
306
+ }
267
307
  /** Formats pairing-required details into the canonical user-facing message. */
268
308
  function formatConnectPairingRequiredMessage(details) {
269
309
  const pairing = readPairingConnectErrorDetails(details);
@@ -274,7 +314,7 @@ function formatConnectPairingRequiredMessage(details) {
274
314
  function formatConnectErrorMessage(params) {
275
315
  if (readConnectErrorDetailCode(params.details) === ConnectErrorDetailCodes.PAIRING_REQUIRED) return formatConnectPairingRequiredMessage(params.details);
276
316
  if (readConnectErrorDetailCode(params.details) === ConnectErrorDetailCodes.PROTOCOL_MISMATCH) return formatProtocolMismatchMessage(params.message, params.details);
277
- return normalizeOptionalString(params.message) ?? "gateway request failed";
317
+ return normalizeOptionalProtocolString(params.message) ?? "gateway request failed";
278
318
  }
279
319
  function formatProtocolMismatchMessage(message, details) {
280
320
  const raw = details;
@@ -286,11 +326,11 @@ function formatProtocolMismatchMessage(message, details) {
286
326
  if (clientMin !== void 0 && clientMax !== void 0) parts.push(clientMin === clientMax ? `Control UI v${clientMin}` : `Control UI v${clientMin}-v${clientMax}`);
287
327
  if (expected !== void 0) parts.push(`Gateway v${expected}`);
288
328
  if (probeMin !== void 0) parts.push(`probe min v${probeMin}`);
289
- const normalized = normalizeOptionalString(message) ?? "protocol mismatch";
329
+ const normalized = normalizeOptionalProtocolString(message) ?? "protocol mismatch";
290
330
  return parts.length > 0 ? `${normalized}: ${parts.join(", ")}` : normalized;
291
331
  }
292
332
  function normalizeProtocolNumber(value) {
293
333
  return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
294
334
  }
295
335
  //#endregion
296
- export { ConnectErrorDetailCodes, buildPairingConnectCloseReason, buildPairingConnectErrorDetails, buildPairingConnectErrorMessage, buildPairingConnectRecoveryTitle, describePairingConnectRequirement, formatConnectErrorMessage, formatConnectPairingRequiredMessage, normalizePairingConnectRequestId, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readConnectPairingRequiredMessage, readPairingConnectErrorDetails, resolveAuthConnectErrorDetailCode, resolveDeviceAuthConnectErrorDetailCode };
336
+ export { ConnectErrorDetailCodes, buildPairingConnectCloseReason, buildPairingConnectErrorDetails, buildPairingConnectErrorMessage, buildPairingConnectRecoveryTitle, classifyGatewayConnectFailure, describePairingConnectRequirement, formatConnectErrorMessage, formatConnectPairingRequiredMessage, normalizePairingConnectRequestId, readConnectErrorDetailCode, readConnectErrorRecoveryAdvice, readConnectPairingRequiredMessage, readControlUiBuildMismatchId, readPairingConnectErrorDetails, resolveAuthConnectErrorDetailCode, resolveDeviceAuthConnectErrorDetailCode };
@@ -1,4 +1,4 @@
1
- import { a as EventFrame, c as GatewayFrame, f as RequestFrame, m as ResponseFrame, r as ErrorShape, t as ConnectParams, u as HelloOk } from "./frames-BPnee-QV.mjs";
1
+ import { a as EventFrame, c as GatewayFrame, f as RequestFrame, m as ResponseFrame, r as ErrorShape, t as ConnectParams, u as HelloOk } from "./frames-B9De7i2H.mjs";
2
2
 
3
3
  //#region src/frame-guards.d.ts
4
4
  declare function isGatewayEventFrame(value: unknown): value is EventFrame;
@@ -1,25 +1,20 @@
1
+ import { n as isNonEmptyProtocolString, r as isProtocolRecord } from "./protocol-value-normalization-Bexl3yr1.mjs";
1
2
  //#region src/frame-guards.ts
2
- function isRecord(value) {
3
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4
- }
5
- function isNonEmptyString(value) {
6
- return typeof value === "string" && value.length > 0;
7
- }
8
3
  function isNonNegativeInteger(value) {
9
4
  return typeof value === "number" && Number.isInteger(value) && value >= 0;
10
5
  }
11
6
  function isGatewayErrorShape(value) {
12
- if (!isRecord(value)) return false;
13
- if (!isNonEmptyString(value.code) || !isNonEmptyString(value.message)) return false;
7
+ if (!isProtocolRecord(value)) return false;
8
+ if (!isNonEmptyProtocolString(value.code) || !isNonEmptyProtocolString(value.message)) return false;
14
9
  if (value.retryable !== void 0 && typeof value.retryable !== "boolean") return false;
15
10
  return value.retryAfterMs === void 0 || isNonNegativeInteger(value.retryAfterMs);
16
11
  }
17
12
  function isGatewayEventFrame(value) {
18
- if (!isRecord(value) || value.type !== "event" || !isNonEmptyString(value.event)) return false;
13
+ if (!isProtocolRecord(value) || value.type !== "event" || !isNonEmptyProtocolString(value.event)) return false;
19
14
  return value.seq === void 0 || isNonNegativeInteger(value.seq);
20
15
  }
21
16
  function isGatewayResponseFrame(value) {
22
- if (!isRecord(value) || value.type !== "res" || !isNonEmptyString(value.id) || typeof value.ok !== "boolean") return false;
17
+ if (!isProtocolRecord(value) || value.type !== "res" || !isNonEmptyProtocolString(value.id) || typeof value.ok !== "boolean") return false;
23
18
  return value.error === void 0 || isGatewayErrorShape(value.error);
24
19
  }
25
20
  //#endregion
@@ -4,7 +4,9 @@ import { Static, Type } from "typebox";
4
4
  declare const GATEWAY_SERVER_CAPS: {
5
5
  readonly BOARD_WIDGET_PUT_CANVAS_DOC: "board-widget-put-canvas-doc";
6
6
  readonly CHAT_SEND_ROUTING_CONTRACT: "chat-send-routing-contract";
7
+ readonly SYSTEM_AGENT_WIZARD_CANCEL: "openclaw-chat-wizard-cancel";
7
8
  readonly SYSTEM_AGENT_SETUP_MODEL_REF: "openclaw-setup-model-ref";
9
+ readonly TASK_SUGGESTIONS_ACCEPT_MODES: "taskSuggestions.acceptModes";
8
10
  };
9
11
  /**
10
12
  * Top-level gateway frame schemas.
@@ -29,6 +31,7 @@ declare const ConnectParamsSchema: Type.TObject<{
29
31
  id: Type.TEnum<["webchat-ui", "openclaw-control-ui", "openclaw-browser-copilot", "openclaw-tui", "webchat", "cli", "gateway-client", "openclaw-macos", "openclaw-linux", "openclaw-ios", "openclaw-watchos", "openclaw-android", "node-host", "openclaw-worker", "test", "fingerprint", "openclaw-probe"]>;
30
32
  displayName: Type.TOptional<Type.TString>;
31
33
  version: Type.TString;
34
+ buildId: Type.TOptional<Type.TString>;
32
35
  platform: Type.TString;
33
36
  deviceFamily: Type.TOptional<Type.TString>;
34
37
  modelIdentifier: Type.TOptional<Type.TString>;
@@ -36,7 +39,13 @@ declare const ConnectParamsSchema: Type.TObject<{
36
39
  instanceId: Type.TOptional<Type.TString>;
37
40
  }>;
38
41
  caps: Type.TOptional<Type.TArray<Type.TString>>;
39
- commands: Type.TOptional<Type.TArray<Type.TString>>;
42
+ commands: Type.TOptional<Type.TArray<Type.TString>>; /** Additive Computer Use declaration; the owning core contract validates its bounded shape. */
43
+ computerUse: Type.TOptional<Type.TUnknown>; /** Additive node-local worker build identity; presence advertises session hosting. */
44
+ workerRuns: Type.TOptional<Type.TObject<{
45
+ bundleHash: Type.TString;
46
+ openclawVersion: Type.TString;
47
+ protocolFeatures: Type.TArray<Type.TString>;
48
+ }>>;
40
49
  permissions: Type.TOptional<Type.TRecord<"^.*$", Type.TBoolean>>;
41
50
  pathEnv: Type.TOptional<Type.TString>;
42
51
  role: Type.TOptional<Type.TString>;
@@ -59,12 +68,14 @@ declare const ConnectParamsSchema: Type.TObject<{
59
68
  locale: Type.TOptional<Type.TString>;
60
69
  userAgent: Type.TOptional<Type.TString>;
61
70
  }>;
62
- /** Successful gateway hello response with negotiated protocol and initial state. */
71
+ /** Successful gateway hello response with the server protocol and initial state. */
63
72
  declare const HelloOkSchema: Type.TObject<{
64
73
  type: Type.TLiteral<"hello-ok">;
65
74
  protocol: Type.TInteger;
66
75
  server: Type.TObject<{
67
76
  version: Type.TString;
77
+ buildId: Type.TOptional<Type.TString>;
78
+ controlUiBuildSource: Type.TOptional<Type.TUnion<[Type.TLiteral<"bundled">, Type.TLiteral<"configured">]>>;
68
79
  connId: Type.TString;
69
80
  }>;
70
81
  features: Type.TObject<{
@@ -104,6 +115,7 @@ declare const HelloOkSchema: Type.TObject<{
104
115
  durationMs: Type.TOptional<Type.TInteger>;
105
116
  eventLoop: Type.TOptional<Type.TObject<{
106
117
  degraded: Type.TBoolean;
118
+ degradedSinceMs: Type.TOptional<Type.TUnion<[Type.TInteger, Type.TNull]>>;
107
119
  reasons: Type.TArray<Type.TUnion<[Type.TLiteral<"event_loop_delay">, Type.TLiteral<"event_loop_utilization">, Type.TLiteral<"cpu">]>>;
108
120
  intervalMs: Type.TNumber;
109
121
  delayP99Ms: Type.TNumber;
@@ -147,6 +159,21 @@ declare const HelloOkSchema: Type.TObject<{
147
159
  count: Type.TInteger;
148
160
  oldestFailedAt: Type.TOptional<Type.TInteger>;
149
161
  }>>;
162
+ ingressFailed: Type.TOptional<Type.TArray<Type.TObject<{
163
+ channelId: Type.TString;
164
+ accountId: Type.TString;
165
+ count: Type.TInteger;
166
+ oldestFailedAt: Type.TOptional<Type.TInteger>;
167
+ }>>>;
168
+ ingressPressure: Type.TOptional<Type.TArray<Type.TObject<{
169
+ channelId: Type.TString;
170
+ accountId: Type.TString;
171
+ laneCount: Type.TInteger;
172
+ pendingCount: Type.TInteger;
173
+ claimedCount: Type.TInteger;
174
+ blockedCount: Type.TInteger;
175
+ oldestReceivedAt: Type.TInteger;
176
+ }>>>;
150
177
  }>>;
151
178
  modelPricing: Type.TOptional<Type.TObject<{
152
179
  state: Type.TUnion<[Type.TLiteral<"ok">, Type.TLiteral<"degraded">, Type.TLiteral<"disabled">]>;
@@ -178,6 +205,7 @@ declare const HelloOkSchema: Type.TObject<{
178
205
  prompt: Type.TString;
179
206
  target: Type.TString;
180
207
  model: Type.TOptional<Type.TString>;
208
+ session: Type.TOptional<Type.TString>;
181
209
  ackMaxChars: Type.TInteger;
182
210
  }>;
183
211
  sessions: Type.TObject<{
@@ -210,6 +238,8 @@ declare const HelloOkSchema: Type.TObject<{
210
238
  stateDir: Type.TOptional<Type.TString>;
211
239
  sessionDefaults: Type.TOptional<Type.TObject<{
212
240
  defaultAgentId: Type.TString;
241
+ ownership: Type.TOptional<Type.TUnion<[Type.TLiteral<"sole">, Type.TLiteral<"legacy">, Type.TLiteral<"explicit">]>>;
242
+ selectionRequired: Type.TOptional<Type.TBoolean>;
213
243
  mainKey: Type.TString;
214
244
  mainSessionKey: Type.TString;
215
245
  scope: Type.TOptional<Type.TString>;
@@ -219,6 +249,70 @@ declare const HelloOkSchema: Type.TObject<{
219
249
  currentVersion: Type.TString;
220
250
  latestVersion: Type.TString;
221
251
  channel: Type.TString;
252
+ currentSha: Type.TOptional<Type.TString>;
253
+ upstreamRef: Type.TOptional<Type.TString>;
254
+ upstreamSha: Type.TOptional<Type.TString>;
255
+ commitsBehind: Type.TOptional<Type.TInteger>;
256
+ commits: Type.TOptional<Type.TArray<Type.TObject<{
257
+ sha: Type.TString;
258
+ subject: Type.TString;
259
+ }>>>;
260
+ }>>;
261
+ updateSchedule: Type.TOptional<Type.TObject<{
262
+ channel: Type.TString;
263
+ autoEnabled: Type.TBoolean;
264
+ install: Type.TOptional<Type.TObject<{
265
+ kind: Type.TUnion<[Type.TLiteral<"package">, Type.TLiteral<"git">, Type.TLiteral<"unknown">]>;
266
+ git: Type.TOptional<Type.TUnion<[Type.TObject<{
267
+ status: Type.TLiteral<"current">;
268
+ currentSha: Type.TOptional<Type.TString>;
269
+ commitAtMs: Type.TOptional<Type.TInteger>;
270
+ installedAtMs: Type.TOptional<Type.TInteger>;
271
+ }>, Type.TObject<{
272
+ status: Type.TLiteral<"behind">;
273
+ commitsBehind: Type.TInteger;
274
+ currentSha: Type.TOptional<Type.TString>;
275
+ commitAtMs: Type.TOptional<Type.TInteger>;
276
+ installedAtMs: Type.TOptional<Type.TInteger>;
277
+ }>, Type.TObject<{
278
+ status: Type.TLiteral<"ahead">;
279
+ commitsAhead: Type.TInteger;
280
+ currentSha: Type.TOptional<Type.TString>;
281
+ commitAtMs: Type.TOptional<Type.TInteger>;
282
+ installedAtMs: Type.TOptional<Type.TInteger>;
283
+ }>, Type.TObject<{
284
+ status: Type.TLiteral<"diverged">;
285
+ commitsAhead: Type.TInteger;
286
+ commitsBehind: Type.TInteger;
287
+ currentSha: Type.TOptional<Type.TString>;
288
+ commitAtMs: Type.TOptional<Type.TInteger>;
289
+ installedAtMs: Type.TOptional<Type.TInteger>;
290
+ }>, Type.TObject<{
291
+ status: Type.TLiteral<"unavailable">;
292
+ reason: Type.TUnion<[Type.TLiteral<"fetch-failed">, Type.TLiteral<"no-upstream">, Type.TLiteral<"no-upstream-sha">, Type.TLiteral<"comparison-failed">, Type.TLiteral<"git-unavailable">]>;
293
+ currentSha: Type.TOptional<Type.TString>;
294
+ commitAtMs: Type.TOptional<Type.TInteger>;
295
+ installedAtMs: Type.TOptional<Type.TInteger>;
296
+ }>]>>;
297
+ }>>;
298
+ target: Type.TOptional<Type.TUnion<[Type.TObject<{
299
+ kind: Type.TLiteral<"package">;
300
+ version: Type.TString;
301
+ }>, Type.TObject<{
302
+ kind: Type.TLiteral<"git">;
303
+ upstreamRef: Type.TString;
304
+ upstreamSha: Type.TString;
305
+ commitsBehind: Type.TInteger;
306
+ }>]>>;
307
+ campaign: Type.TOptional<Type.TObject<{
308
+ id: Type.TString;
309
+ state: Type.TUnion<[Type.TLiteral<"waiting-for-idle">, Type.TLiteral<"countdown">, Type.TLiteral<"applying">]>;
310
+ announcedAtMs: Type.TInteger;
311
+ applyAtMs: Type.TOptional<Type.TInteger>;
312
+ holdUntilMs: Type.TOptional<Type.TInteger>;
313
+ forceAtMs: Type.TInteger;
314
+ updatedAtMs: Type.TInteger;
315
+ }>>;
222
316
  }>>;
223
317
  }>;
224
318
  controlUiTabs: Type.TOptional<Type.TArray<Type.TObject<{
@@ -243,6 +337,8 @@ declare const HelloOkSchema: Type.TObject<{
243
337
  }>>;
244
338
  auth: Type.TObject<{
245
339
  deviceToken: Type.TOptional<Type.TString>;
340
+ recoveryMigrationAllowed: Type.TOptional<Type.TLiteral<true>>;
341
+ recoveryScope: Type.TOptional<Type.TString>;
246
342
  role: Type.TString;
247
343
  scopes: Type.TArray<Type.TString>;
248
344
  issuedAtMs: Type.TOptional<Type.TInteger>;
@@ -257,6 +353,10 @@ declare const HelloOkSchema: Type.TObject<{
257
353
  maxPayload: Type.TInteger;
258
354
  maxBufferedBytes: Type.TInteger;
259
355
  tickIntervalMs: Type.TInteger;
356
+ attachments: Type.TOptional<Type.TObject<{
357
+ maxBytes: Type.TInteger;
358
+ maxImageBytes: Type.TInteger;
359
+ }>>;
260
360
  allowedSessionVisibilities: Type.TOptional<Type.TArray<Type.TUnion<[Type.TLiteral<"shared">, Type.TLiteral<"read-only">, Type.TLiteral<"suggest">, Type.TLiteral<"draft">]>>>;
261
361
  hasMultipleSessionSharingIdentities: Type.TOptional<Type.TBoolean>;
262
362
  }>;
@@ -1,8 +1,8 @@
1
1
  //#region src/gateway-error-details.d.ts
2
2
  /** Gateway JSON-RPC style error codes shared by clients and server handlers. */
3
3
  declare const ErrorCodes: {
4
- /** Client has not completed account/device linking for this gateway. */readonly NOT_LINKED: "NOT_LINKED"; /** Device exists but still needs an explicit pairing approval. */
5
- readonly NOT_PAIRED: "NOT_PAIRED"; /** Agent turn exceeded the gateway wait window. */
4
+ /** @deprecated Retained for source compatibility; no current server emitter. */readonly NOT_LINKED: "NOT_LINKED"; /** Device exists but still needs an explicit pairing approval. */
5
+ readonly NOT_PAIRED: "NOT_PAIRED"; /** @deprecated Retained for source compatibility; no current server emitter. */
6
6
  readonly AGENT_TIMEOUT: "AGENT_TIMEOUT"; /** Request payload failed protocol validation or method preconditions. */
7
7
  readonly INVALID_REQUEST: "INVALID_REQUEST"; /** Authenticated caller lacks permission for the requested operation. */
8
8
  readonly FORBIDDEN: "FORBIDDEN"; /** Approval resolution referenced a missing or expired approval request. */
@@ -15,7 +15,9 @@ type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
15
15
  declare const GatewayErrorDetailCodes: {
16
16
  readonly MISSING_SCOPE: "MISSING_SCOPE";
17
17
  readonly MCP_APP_VIEW_EXPIRED: "MCP_APP_VIEW_EXPIRED";
18
+ readonly USER_PREFS_LIMIT_EXCEEDED: "USER_PREFS_LIMIT_EXCEEDED";
18
19
  readonly SESSION_COMPANION_BUSY: "SESSION_COMPANION_BUSY";
20
+ readonly PROJECT_CLONE_FAILED: "PROJECT_CLONE_FAILED";
19
21
  readonly UNKNOWN_AGENT_ID: "UNKNOWN_AGENT_ID";
20
22
  readonly WIZARD_NOT_FOUND: "WIZARD_NOT_FOUND";
21
23
  };
@@ -28,6 +30,12 @@ type MissingScopeErrorDetails = {
28
30
  type McpAppViewExpiredErrorDetails = {
29
31
  code: typeof GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
30
32
  };
33
+ /** Per-profile preference quota details returned by users.prefs.set. */
34
+ type UserPrefsLimitExceededErrorDetails = {
35
+ code: typeof GatewayErrorDetailCodes.USER_PREFS_LIMIT_EXCEEDED;
36
+ limit: number;
37
+ currentCount: number;
38
+ };
31
39
  /** Unknown agent details carried by agent-scoped method validation failures. */
32
40
  type UnknownAgentIdErrorDetails = {
33
41
  code: typeof GatewayErrorDetailCodes.UNKNOWN_AGENT_ID;
@@ -37,8 +45,13 @@ type UnknownAgentIdErrorDetails = {
37
45
  type WizardNotFoundErrorDetails = {
38
46
  code: typeof GatewayErrorDetailCodes.WIZARD_NOT_FOUND;
39
47
  };
48
+ type ProjectCloneFailureCause = "invalid_url" | "auth_required" | "not_found" | "network" | "target_exists" | "clone_failed";
49
+ type ProjectCloneErrorDetails = {
50
+ code: typeof GatewayErrorDetailCodes.PROJECT_CLONE_FAILED;
51
+ cause: ProjectCloneFailureCause;
52
+ };
40
53
  /** Structured details emitted by method-level failures. */
41
- type GatewayErrorDetails = MissingScopeErrorDetails | McpAppViewExpiredErrorDetails | UnknownAgentIdErrorDetails | WizardNotFoundErrorDetails;
54
+ type GatewayErrorDetails = MissingScopeErrorDetails | McpAppViewExpiredErrorDetails | UserPrefsLimitExceededErrorDetails | ProjectCloneErrorDetails | UnknownAgentIdErrorDetails | WizardNotFoundErrorDetails;
42
55
  /** Reads validated missing-scope details from an untrusted protocol payload. */
43
56
  declare function readMissingScopeErrorDetails(details: unknown): MissingScopeErrorDetails | null;
44
57
  declare function isMcpAppViewExpiredError(error: unknown): boolean;
@@ -48,4 +61,4 @@ declare function isMcpAppViewExpiredError(error: unknown): boolean;
48
61
  */
49
62
  declare function readMissingScopeError(error: unknown): MissingScopeErrorDetails | null;
50
63
  //#endregion
51
- export { McpAppViewExpiredErrorDetails as a, WizardNotFoundErrorDetails as c, readMissingScopeErrorDetails as d, GatewayErrorDetails as i, isMcpAppViewExpiredError as l, ErrorCodes as n, MissingScopeErrorDetails as o, GatewayErrorDetailCodes as r, UnknownAgentIdErrorDetails as s, ErrorCode as t, readMissingScopeError as u };
64
+ export { McpAppViewExpiredErrorDetails as a, ProjectCloneFailureCause as c, WizardNotFoundErrorDetails as d, isMcpAppViewExpiredError as f, GatewayErrorDetails as i, UnknownAgentIdErrorDetails as l, readMissingScopeErrorDetails as m, ErrorCodes as n, MissingScopeErrorDetails as o, readMissingScopeError as p, GatewayErrorDetailCodes as r, ProjectCloneErrorDetails as s, ErrorCode as t, UserPrefsLimitExceededErrorDetails as u };
@@ -1,2 +1,2 @@
1
- import { a as McpAppViewExpiredErrorDetails, c as WizardNotFoundErrorDetails, d as readMissingScopeErrorDetails, i as GatewayErrorDetails, l as isMcpAppViewExpiredError, n as ErrorCodes, o as MissingScopeErrorDetails, r as GatewayErrorDetailCodes, s as UnknownAgentIdErrorDetails, t as ErrorCode, u as readMissingScopeError } from "./gateway-error-details-Btc09cgL.mjs";
2
- export { ErrorCode, ErrorCodes, GatewayErrorDetailCodes, GatewayErrorDetails, McpAppViewExpiredErrorDetails, MissingScopeErrorDetails, UnknownAgentIdErrorDetails, WizardNotFoundErrorDetails, isMcpAppViewExpiredError, readMissingScopeError, readMissingScopeErrorDetails };
1
+ import { a as McpAppViewExpiredErrorDetails, c as ProjectCloneFailureCause, d as WizardNotFoundErrorDetails, f as isMcpAppViewExpiredError, i as GatewayErrorDetails, l as UnknownAgentIdErrorDetails, m as readMissingScopeErrorDetails, n as ErrorCodes, o as MissingScopeErrorDetails, p as readMissingScopeError, r as GatewayErrorDetailCodes, s as ProjectCloneErrorDetails, t as ErrorCode, u as UserPrefsLimitExceededErrorDetails } from "./gateway-error-details-BXoMHq1i.mjs";
2
+ export { ErrorCode, ErrorCodes, GatewayErrorDetailCodes, GatewayErrorDetails, McpAppViewExpiredErrorDetails, MissingScopeErrorDetails, ProjectCloneErrorDetails, ProjectCloneFailureCause, UnknownAgentIdErrorDetails, UserPrefsLimitExceededErrorDetails, WizardNotFoundErrorDetails, isMcpAppViewExpiredError, readMissingScopeError, readMissingScopeErrorDetails };
@@ -1,11 +1,12 @@
1
+ import { t as asProtocolRecord } from "./protocol-value-normalization-Bexl3yr1.mjs";
1
2
  //#region src/gateway-error-details.ts
2
3
  /** Gateway JSON-RPC style error codes shared by clients and server handlers. */
3
4
  const ErrorCodes = {
4
- /** Client has not completed account/device linking for this gateway. */
5
+ /** @deprecated Retained for source compatibility; no current server emitter. */
5
6
  NOT_LINKED: "NOT_LINKED",
6
7
  /** Device exists but still needs an explicit pairing approval. */
7
8
  NOT_PAIRED: "NOT_PAIRED",
8
- /** Agent turn exceeded the gateway wait window. */
9
+ /** @deprecated Retained for source compatibility; no current server emitter. */
9
10
  AGENT_TIMEOUT: "AGENT_TIMEOUT",
10
11
  /** Request payload failed protocol validation or method preconditions. */
11
12
  INVALID_REQUEST: "INVALID_REQUEST",
@@ -20,17 +21,16 @@ const ErrorCodes = {
20
21
  const GatewayErrorDetailCodes = {
21
22
  MISSING_SCOPE: "MISSING_SCOPE",
22
23
  MCP_APP_VIEW_EXPIRED: "MCP_APP_VIEW_EXPIRED",
24
+ USER_PREFS_LIMIT_EXCEEDED: "USER_PREFS_LIMIT_EXCEEDED",
23
25
  SESSION_COMPANION_BUSY: "SESSION_COMPANION_BUSY",
26
+ PROJECT_CLONE_FAILED: "PROJECT_CLONE_FAILED",
24
27
  UNKNOWN_AGENT_ID: "UNKNOWN_AGENT_ID",
25
28
  WIZARD_NOT_FOUND: "WIZARD_NOT_FOUND"
26
29
  };
27
30
  const LEGACY_MISSING_SCOPE_PATTERN = /\bmissing scope:\s*([a-z0-9._-]+)/i;
28
- function asRecord(value) {
29
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
30
- }
31
31
  /** Reads validated missing-scope details from an untrusted protocol payload. */
32
32
  function readMissingScopeErrorDetails(details) {
33
- const record = asRecord(details);
33
+ const record = asProtocolRecord(details);
34
34
  if (record?.code !== GatewayErrorDetailCodes.MISSING_SCOPE) return null;
35
35
  const missingScope = typeof record.missingScope === "string" ? record.missingScope.trim() : "";
36
36
  const requiredScopes = Array.isArray(record.requiredScopes) ? record.requiredScopes.map((scope) => typeof scope === "string" ? scope.trim() : "") : [];
@@ -42,14 +42,14 @@ function readMissingScopeErrorDetails(details) {
42
42
  };
43
43
  }
44
44
  function isMcpAppViewExpiredError(error) {
45
- return asRecord(asRecord(error)?.details)?.code === GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
45
+ return asProtocolRecord(asProtocolRecord(error)?.details)?.code === GatewayErrorDetailCodes.MCP_APP_VIEW_EXPIRED;
46
46
  }
47
47
  /**
48
48
  * Reads a method-level missing-scope failure, preferring structured details.
49
49
  * The message fallback keeps clients compatible with gateways predating structured details.
50
50
  */
51
51
  function readMissingScopeError(error) {
52
- const record = asRecord(error);
52
+ const record = asProtocolRecord(error);
53
53
  if (!record) return null;
54
54
  const structured = readMissingScopeErrorDetails(record.details);
55
55
  if (structured) return structured;