From de82d17de2a7964bfa05988698f019ffe7801f1e Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 3 May 2026 16:50:32 -0700 Subject: [PATCH] fix(qa): require cache probe marker --- CHANGELOG.md | 1 + src/agents/live-cache-regression-runner.test.ts | 7 +++++++ src/agents/live-cache-regression-runner.ts | 13 +++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a06e139a48a..7e3a7ebba88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ Docs: https://docs.openclaw.ai - Channels/WhatsApp: allow `@whiskeysockets/libsignal-node` in `onlyBuiltDependencies` so pnpm v9+ `blockExoticSubdeps` no longer rejects the baileys git-tarball subdep and silences all inbound agent replies. Fixes #76539. Thanks @ottodeng and @vincentkoc. - Gateway/systemd: preserve operator-added secrets in the Gateway env file across re-stage while clearing OpenClaw-managed keys (such as `OPENCLAW_GATEWAY_TOKEN`) so a fresh staging value is never shadowed by a stale env-file copy; operator secrets are also retained when the state-dir `.env` is empty. Fixes #76860. Thanks @hclsys. +- QA/cache: require the full `CACHE-OK ` marker before live cache probes stop retrying, so suffix-only prose cannot hide a broken probe response. Thanks @vincentkoc. - Slack/Matrix: avoid creating blank progress-draft messages when `streaming.progress.label=false` and progress tool lines are disabled. Thanks @vincentkoc. - QA/Matrix: keep the mock OpenAI tool-progress provider aligned with exact-marker Matrix prompts so the hardened live preview scenario still forces a deterministic read before final delivery. Thanks @vincentkoc. - OpenAI/Google Meet: wait for realtime voice `session.updated` before treating the bridge as connected, so Meet joins do not return with audio queued behind an unconfigured realtime session. Thanks @vincentkoc. diff --git a/src/agents/live-cache-regression-runner.test.ts b/src/agents/live-cache-regression-runner.test.ts index ecd30005732..97bc267836f 100644 --- a/src/agents/live-cache-regression-runner.test.ts +++ b/src/agents/live-cache-regression-runner.test.ts @@ -99,6 +99,13 @@ describe("live cache regression runner", () => { text: "", }), ).toBe(false); + expect( + __testing.shouldRetryCacheProbeText({ + attempt: 1, + suffix: "openai-stable-hit-a", + text: "I saw openai-stable-hit-a.", + }), + ).toBe(true); expect( __testing.shouldRetryCacheProbeText({ attempt: 1, diff --git a/src/agents/live-cache-regression-runner.ts b/src/agents/live-cache-regression-runner.ts index f47fbebc1fe..c0c54d046d9 100644 --- a/src/agents/live-cache-regression-runner.ts +++ b/src/agents/live-cache-regression-runner.ts @@ -136,7 +136,11 @@ function shouldRetryCacheProbeText(params: { }): boolean { const responseTextLower = normalizeLowercaseStringOrEmpty(params.text); const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix); - return !responseTextLower.includes(suffixLower) && params.attempt <= LIVE_CACHE_RESPONSE_RETRIES; + const markerLower = `cache-ok ${suffixLower}`; + return ( + (!responseTextLower.includes(markerLower) || !responseTextLower.includes(suffixLower)) && + params.attempt <= LIVE_CACHE_RESPONSE_RETRIES + ); } async function runToolOnlyTurn(params: { @@ -244,9 +248,10 @@ async function completeCacheProbe(params: { } const responseTextLower = normalizeLowercaseStringOrEmpty(text); const suffixLower = normalizeLowercaseStringOrEmpty(params.suffix); + const markerLower = `cache-ok ${suffixLower}`; assert( - responseTextLower.includes(suffixLower), - `expected response to contain ${params.suffix}, got ${JSON.stringify(text)}`, + responseTextLower.includes(markerLower), + `expected response to contain CACHE-OK ${params.suffix}, got ${JSON.stringify(text)}`, ); const usage = normalizeCacheUsage(response.usage); return { @@ -256,7 +261,7 @@ async function completeCacheProbe(params: { hitRate: computeCacheHitRate(usage), }; } - throw new Error(`expected response to contain ${params.suffix}`); + throw new Error(`expected response to contain CACHE-OK ${params.suffix}`); } async function runRepeatedLane(params: {