test: repair gateway client boundary snapshots

This commit is contained in:
Peter Steinberger
2026-05-29 03:40:00 +01:00
parent 9ca791288c
commit a4ff3e19ea
7 changed files with 116 additions and 64 deletions

View File

@@ -515,30 +515,46 @@ describe("GatewayChatClient", () => {
vi.useRealTimers();
});
it("identifies the TUI as a tui client and skips device identity on insecure local ui paths", () => {
const client = new GatewayChatClient({
url: "ws://127.0.0.1:18789",
token: "test-token",
preauthHandshakeTimeoutMs: 30_000,
allowInsecureLocalOperatorUi: true,
it("identifies the TUI as a tui client and skips device identity on insecure local ui paths", async () => {
const constructedOptions: Array<Record<string, unknown>> = [];
vi.resetModules();
vi.doMock("../gateway/client.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../gateway/client.js")>();
class CapturingGatewayClient {
constructor(opts: Record<string, unknown>) {
constructedOptions.push(opts);
}
start() {}
stop() {}
request() {
throw new Error("unexpected request");
}
}
return { ...actual, GatewayClient: CapturingGatewayClient };
});
expect(
(client as unknown as { client: { opts: { clientName?: string; mode?: string } } }).client
.opts.clientName,
).toBe("openclaw-tui");
expect(
(client as unknown as { client: { opts: { clientName?: string; mode?: string } } }).client
.opts.mode,
).toBe("ui");
expect(
(client as unknown as { client: { opts: { deviceIdentity?: unknown } } }).client.opts
.deviceIdentity,
).toBeUndefined();
expect(
(client as unknown as { client: { opts: { preauthHandshakeTimeoutMs?: number } } }).client
.opts.preauthHandshakeTimeoutMs,
).toBe(30_000);
try {
const { GatewayChatClient: CapturingGatewayChatClient } = await import("./gateway-chat.js");
const client = new CapturingGatewayChatClient({
url: "ws://127.0.0.1:18789",
token: "test-token",
preauthHandshakeTimeoutMs: 30_000,
allowInsecureLocalOperatorUi: true,
});
expect(client.connection.allowInsecureLocalOperatorUi).toBe(true);
expect(constructedOptions).toHaveLength(1);
expect(constructedOptions[0]).toMatchObject({
clientName: "openclaw-tui",
mode: "ui",
preauthHandshakeTimeoutMs: 30_000,
deviceIdentity: null,
});
} finally {
vi.doUnmock("../gateway/client.js");
vi.resetModules();
}
});
it("surfaces loopback block-mode start failures through disconnect handler", async () => {

View File

@@ -262,7 +262,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -270,7 +271,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -329,6 +331,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -346,7 +349,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -354,7 +358,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -367,7 +372,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",
@@ -480,7 +486,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -488,7 +495,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -547,6 +555,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -564,7 +573,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -572,7 +582,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -585,7 +596,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",

View File

@@ -262,7 +262,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -270,7 +271,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -329,6 +331,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -346,7 +349,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -354,7 +358,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -367,7 +372,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",
@@ -480,7 +486,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -488,7 +495,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -547,6 +555,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -564,7 +573,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -572,7 +582,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -585,7 +596,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",

View File

@@ -262,7 +262,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -270,7 +271,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -329,6 +331,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -346,7 +349,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -354,7 +358,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -367,7 +372,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",
@@ -480,7 +486,8 @@
},
"after": {
"description": "Failures before alert",
"type": "number"
"minimum": 1,
"type": "integer"
},
"channel": {
"description": "Alert channel",
@@ -488,7 +495,8 @@
},
"cooldownMs": {
"description": "Alert cooldown ms",
"type": "number"
"minimum": 0,
"type": "integer"
},
"includeSkipped": {
"description": "Skipped runs count toward alert",
@@ -547,6 +555,7 @@
"type": "string"
},
"timeoutSeconds": {
"minimum": 0,
"type": "number"
},
"toolsAllow": {
@@ -564,7 +573,8 @@
"properties": {
"anchorMs": {
"description": "Start anchor ms (kind=every)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"at": {
"description": "ISO-8601 time (kind=at)",
@@ -572,7 +582,8 @@
},
"everyMs": {
"description": "Interval ms (kind=every)",
"type": "number"
"minimum": 1,
"type": "integer"
},
"expr": {
"description": "Cron expr in tz wall-clock time; do not convert to UTC. Omitted tz => Gateway host local timezone. Example 6pm Shanghai daily: expr \"0 18 * * *\", tz \"Asia/Shanghai\".",
@@ -585,7 +596,8 @@
},
"staggerMs": {
"description": "Jitter ms (kind=cron)",
"type": "number"
"minimum": 0,
"type": "integer"
},
"tz": {
"description": "IANA timezone for cron wall-clock fields, e.g. \"Asia/Shanghai\"; omitted => Gateway host local timezone.",

View File

@@ -221,8 +221,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 40744,
"roughTokens": 10186
"chars": 41138,
"roughTokens": 10285
},
"openClawDeveloperInstructions": {
"chars": 2988,
@@ -233,8 +233,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6925
},
"totalWithDynamicToolsJson": {
"chars": 68446,
"roughTokens": 17112
"chars": 68840,
"roughTokens": 17210
},
"userInputText": {
"chars": 1629,

View File

@@ -221,8 +221,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 40465,
"roughTokens": 10117
"chars": 40859,
"roughTokens": 10215
},
"openClawDeveloperInstructions": {
"chars": 1964,
@@ -233,8 +233,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6544
},
"totalWithDynamicToolsJson": {
"chars": 66643,
"roughTokens": 16661
"chars": 67037,
"roughTokens": 16760
},
"userInputText": {
"chars": 1129,

View File

@@ -222,8 +222,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 0
},
"dynamicToolsJson": {
"chars": 41560,
"roughTokens": 10390
"chars": 41954,
"roughTokens": 10489
},
"openClawDeveloperInstructions": {
"chars": 1983,
@@ -234,8 +234,8 @@ This is the deterministic model-bound layer stack OpenClaw can snapshot for the
"roughTokens": 6780
},
"totalWithDynamicToolsJson": {
"chars": 68681,
"roughTokens": 17171
"chars": 69075,
"roughTokens": 17269
},
"userInputText": {
"chars": 1367,