From de2679f6d18a1728c875b45101277ca4d7cd04f3 Mon Sep 17 00:00:00 2001 From: backryun Date: Mon, 10 Aug 2026 12:28:07 +0900 Subject: [PATCH] fix(types): stabilize skill token extraction (#9920) --- src/lib/skills/injection.ts | 2 +- tests/unit/skills-injection.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib/skills/injection.ts b/src/lib/skills/injection.ts index c5a63e2077..f66af58b8f 100644 --- a/src/lib/skills/injection.ts +++ b/src/lib/skills/injection.ts @@ -73,7 +73,7 @@ function toLowerText(value: unknown): string { } function extractTokens(value: string): Set { - const matches = value.toLowerCase().match(/[a-z0-9]+/g) || []; + const matches: string[] = value.toLowerCase().match(/[a-z0-9]+/g) ?? []; return new Set(matches.filter((t) => t.length >= TOKEN_MIN_LEN)); } diff --git a/tests/unit/skills-injection.test.ts b/tests/unit/skills-injection.test.ts index 51eca71a9e..777ac88de1 100644 --- a/tests/unit/skills-injection.test.ts +++ b/tests/unit/skills-injection.test.ts @@ -186,6 +186,32 @@ test("injectSkills auto mode matches message/context semantics and applies score }); }); +test("injectSkills auto mode only scores name tokens with at least three characters", async () => { + for (const name of ["aiSearch", "apiSearch"]) { + await skillRegistry.register({ + name, + version: "1.0.0", + description: "find", + schema: { input: {}, output: {} }, + handler: `${name}-handler`, + enabled: true, + mode: "auto", + apiKeyId: "key-token-length", + }); + } + + const tools = injectSkills({ + provider: "other", + apiKeyId: "key-token-length", + messages: [{ role: "user", content: "ai api find" }], + }); + + assert.deepEqual( + tools.map((tool) => (tool as { function: { name: string } }).function.name), + ["apiSearch@1.0.0"] + ); +}); + test("injectSkills auto mode prefers provider-matching tagged skills", async () => { await skillRegistry.register({ name: "openaiDocTool",