From 560ecafa2dfdc8f5bf2a21f9212bfd971d10ea7d Mon Sep 17 00:00:00 2001 From: ly-wang19 <94427531+ly-wang19@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:51:55 +0800 Subject: [PATCH] fix(model-param-b): match both adjacent b tokens sharing one delimiter (#96288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inferParamBFromIdOrName used a consuming trailing boundary `b(?:[^a-z0-9]|$)`, so when two `b` parameter tokens are separated by a single delimiter ("8b 70b", "8b-70b"), the first match ate the shared delimiter and the second token's required leading boundary had nothing to match, silently skipping it — returning the first (often smaller) size instead of the largest. Make the trailing boundary a non-consuming lookahead. Co-authored-by: ly-wang19 Co-authored-by: Claude Opus 4.8 (1M context) --- src/shared/model-param-b.test.ts | 6 ++++++ src/shared/model-param-b.ts | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/shared/model-param-b.test.ts b/src/shared/model-param-b.test.ts index 5359f3bc39d..c50a1064b7c 100644 --- a/src/shared/model-param-b.test.ts +++ b/src/shared/model-param-b.test.ts @@ -10,6 +10,12 @@ describe("shared/model-param-b", () => { expect(inferParamBFromIdOrName("(70b) + m1.5b + qwen-14b")).toBe(70); }); + it("matches both tokens when two are separated by a single delimiter", () => { + expect(inferParamBFromIdOrName("8b 70b")).toBe(70); + expect(inferParamBFromIdOrName("8b-70b")).toBe(70); + expect(inferParamBFromIdOrName("7b-13b")).toBe(13); + }); + it("ignores malformed, zero, and non-delimited matches", () => { expect(inferParamBFromIdOrName("abc70beta 0b x70b2")).toBeNull(); expect(inferParamBFromIdOrName("model 0b")).toBeNull(); diff --git a/src/shared/model-param-b.ts b/src/shared/model-param-b.ts index 6c564ee5d4f..1c89609c59e 100644 --- a/src/shared/model-param-b.ts +++ b/src/shared/model-param-b.ts @@ -4,7 +4,9 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/st /** Infers the largest `b` parameter-size token from a model id or display name. */ export function inferParamBFromIdOrName(text: string): number | null { const raw = normalizeLowercaseStringOrEmpty(text); - const matches = raw.matchAll(/(?:^|[^a-z0-9])[a-z]?(\d+(?:\.\d+)?)b(?:[^a-z0-9]|$)/g); + // Trailing boundary is a lookahead so two adjacent `b` tokens sharing one delimiter (e.g. + // "8b 70b" / "8b-70b") both match; a consuming boundary ate the delimiter and skipped the second. + const matches = raw.matchAll(/(?:^|[^a-z0-9])[a-z]?(\d+(?:\.\d+)?)b(?=[^a-z0-9]|$)/g); let best: number | null = null; for (const match of matches) { const numRaw = match[1];