From ac99494e443d76123480e38dbffdb6adbbed3090 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 16 May 2026 22:37:33 +0100 Subject: [PATCH] test: tighten session_status run-session proof (#82696) --- CHANGELOG.md | 1 + ...sion-status-run-session-key-live-proof.mjs | 70 ++++++++++++++----- .../openclaw-tools.session-status.test.ts | 5 +- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 619096a6c3d..5330b9a0cd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai - Providers/OpenAI Codex: include base `gpt-5.5` and `gpt-5.4` reasoning metadata in the bundled Codex catalog so `/think xhigh` remains available for those models. Fixes #82744. - Agents/edit tool: honor `file_path` and related path aliases when resolving edit-recovery targets, so post-write errors no longer surface false edit failures after the file actually changed. Fixes #81909. Thanks @giodl73-repo. - QQBot: treat only explicit truthy `QQBOT_DEBUG` values as enabling debug logs, so false-like values such as `0` no longer expose debug output. Fixes #82644. (#82697) Thanks @leno23. +- Agents/session_status: resolve implicit no-arg status lookups against the live run session, so `/think` changes report the current thinking level instead of stale sandbox state. Fixes #82669. (#82696) Thanks @leno23. - Gateway/diagnostics: add opt-in critical memory pressure stability snapshots with gateway logs, V8 heap, cgroup, active-resource, and redacted large session-file evidence. Fixes #82518. - Doctor/Gateway: avoid treating unrelated macOS LaunchAgents as legacy gateways just because their environment values mention old checkout paths. - CLI/setup: collapse raw gateway config keys in existing-config summaries into friendly `Model` and `Gateway` rows. diff --git a/scripts/repro/session-status-run-session-key-live-proof.mjs b/scripts/repro/session-status-run-session-key-live-proof.mjs index 229ced4c23b..28a337f108e 100644 --- a/scripts/repro/session-status-run-session-key-live-proof.mjs +++ b/scripts/repro/session-status-run-session-key-live-proof.mjs @@ -6,9 +6,9 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { createSessionStatusTool } from "../../src/agents/tools/session-status-tool.ts"; const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-session-status-proof-")); +const configPath = path.join(tmpRoot, "openclaw.json"); const storePath = path.join(tmpRoot, "sessions.json"); const store = { "agent:main:telegram:default:direct:1234": { @@ -24,13 +24,32 @@ const store = { thinkingLevel: "high", }, }; +fs.writeFileSync(configPath, "{}\n"); fs.writeFileSync(storePath, `${JSON.stringify(store, null, 2)}\n`); +process.env.OPENCLAW_CONFIG_PATH = configPath; +process.env.OPENCLAW_DISABLE_BUNDLED_PLUGINS = "1"; + +const originalStderrWrite = process.stderr.write.bind(process.stderr); +process.stderr.write = (chunk, encoding, callback) => { + const text = String(chunk); + if (text.includes("gateway connect failed:")) { + if (typeof encoding === "function") { + encoding(); + } else if (typeof callback === "function") { + callback(); + } + return true; + } + return originalStderrWrite(chunk, encoding, callback); +}; + +const { createSessionStatusTool } = await import("../../src/agents/tools/session-status-tool.ts"); const config = { session: { mainKey: "main", scope: "per-sender", store: storePath }, agents: { defaults: { - model: { primary: "openai/gpt-5.4" }, + model: { primary: "proof/gpt-5.4" }, models: {}, }, }, @@ -39,22 +58,37 @@ const config = { }, }; -const tool = createSessionStatusTool({ - agentSessionKey: "agent:main:telegram:default:direct:1234", - runSessionKey: "agent:main:main", - config, -}); +try { + const tool = createSessionStatusTool({ + agentSessionKey: "agent:main:telegram:default:direct:1234", + runSessionKey: "agent:main:main", + config, + }); -const result = await tool.execute("live-proof-implicit-run-session", {}); -const text = typeof result === "string" ? result : JSON.stringify(result); -const thinkingMatch = text.match(/think(?:ing)?[:\s]+(\w+)/i); + const result = await tool.execute("live-proof-implicit-run-session", {}); + const text = + typeof result === "string" + ? result + : (result.content.find((item) => item.type === "text")?.text ?? result.details.statusText); + const thinkingMatch = text.match(/\bThink:\s+(\w+)/i); + const sessionKey = typeof result === "string" ? undefined : result.details.sessionKey; -console.log( - "implicit session_status resolved thinkingLevel from store =", - store["agent:main:main"].thinkingLevel, -); -console.log("status text mentions thinking:", thinkingMatch?.[1] ?? "(see full status below)"); -console.log("--- status excerpt ---"); -console.log(text.split("\n").slice(0, 12).join("\n")); + if (sessionKey !== "agent:main:main") { + throw new Error(`expected details.sessionKey agent:main:main, got ${String(sessionKey)}`); + } + if (thinkingMatch?.[1] !== "high") { + throw new Error(`expected status text to mention Think: high, got ${thinkingMatch?.[1]}`); + } -fs.rmSync(tmpRoot, { recursive: true, force: true }); + console.log( + "implicit session_status resolved thinkingLevel from store =", + store["agent:main:main"].thinkingLevel, + ); + console.log("status text mentions thinking:", thinkingMatch[1]); + console.log("details.sessionKey =", sessionKey); + console.log("--- status excerpt ---"); + console.log(text.split("\n").slice(0, 8).join("\n")); +} finally { + process.stderr.write = originalStderrWrite; + fs.rmSync(tmpRoot, { recursive: true, force: true }); +} diff --git a/src/agents/openclaw-tools.session-status.test.ts b/src/agents/openclaw-tools.session-status.test.ts index a65e9011ec5..77620ec95e5 100644 --- a/src/agents/openclaw-tools.session-status.test.ts +++ b/src/agents/openclaw-tools.session-status.test.ts @@ -556,7 +556,10 @@ describe("session_status tool", () => { config: mockConfig as never, }); - await tool.execute("call-implicit-run-session-thinking", {}); + const result = await tool.execute("call-implicit-run-session-thinking", {}); + const details = result.details as { ok?: boolean; sessionKey?: string }; + expect(details.ok).toBe(true); + expect(details.sessionKey).toBe("agent:main:main"); const statusArg = mockCallArg(buildStatusMessageMock) as Record; const sessionEntry = statusArg.sessionEntry as SessionEntry;