惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
IT之家
IT之家
Recent Announcements
Recent Announcements
B
Blog
D
Docker
V
V2EX
GbyAI
GbyAI
L
LangChain Blog
博客园 - Franky
U
Unit 42
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Vercel News
Vercel News
博客园_首页
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
量子位
Blog — PlanetScale
Blog — PlanetScale
罗磊的独立博客

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: pin query expansion expectations · openclaw/opencla...
shakkernerd · 2026-05-12 · via Recent Commits to openclaw:main

@@ -1,27 +1,10 @@

11

import { describe, expect, it } from "vitest";

22

import { expandQueryForFts, extractKeywords } from "./query-expansion.js";

334-

function countKeyword(keywords: readonly string[], keyword: string): number {

5-

let count = 0;

6-

for (const candidate of keywords) {

7-

if (candidate === keyword) {

8-

count++;

9-

}

10-

}

11-

return count;

12-

}

13-144

describe("extractKeywords", () => {

155

it("extracts keywords from English conversational query", () => {

166

const keywords = extractKeywords("that thing we discussed about the API");

17-

expect(keywords).toContain("discussed");

18-

expect(keywords).toContain("api");

19-

// Should not include stop words

20-

expect(keywords).not.toContain("that");

21-

expect(keywords).not.toContain("thing");

22-

expect(keywords).not.toContain("we");

23-

expect(keywords).not.toContain("about");

24-

expect(keywords).not.toContain("the");

7+

expect(keywords).toStrictEqual(["discussed", "api"]);

258

});

2692710

it("extracts keywords from Chinese conversational query", () => {

@@ -43,25 +26,17 @@ describe("extractKeywords", () => {

43264427

it("returns specific technical terms", () => {

4528

const keywords = extractKeywords("what was the solution for the CFR bug");

46-

expect(keywords).toContain("solution");

47-

expect(keywords).toContain("cfr");

48-

expect(keywords).toContain("bug");

29+

expect(keywords).toStrictEqual(["solution", "cfr", "bug"]);

4930

});

50315132

it("extracts keywords from Korean conversational query", () => {

5233

const keywords = extractKeywords("어제 논의한 배포 전략");

53-

expect(keywords).toContain("논의한");

54-

expect(keywords).toContain("배포");

55-

expect(keywords).toContain("전략");

56-

// Should not include stop words

57-

expect(keywords).not.toContain("어제");

34+

expect(keywords).toStrictEqual(["논의한", "배포", "전략"]);

5835

});

59366037

it("strips Korean particles to extract stems", () => {

6138

const keywords = extractKeywords("서버에서 발생한 에러를 확인");

62-

expect(keywords).toContain("서버");

63-

expect(keywords).toContain("에러");

64-

expect(keywords).toContain("확인");

39+

expect(keywords).toStrictEqual(["서버에서", "서버", "발생한", "에러를", "에러", "확인"]);

6540

});

66416742

it("filters Korean stop words including inflected forms", () => {

@@ -88,14 +63,12 @@ describe("extractKeywords", () => {

88638964

it("strips longest Korean trailing particles first", () => {

9065

const keywords = extractKeywords("기능으로 설명");

91-

expect(keywords).toContain("기능");

92-

expect(keywords).not.toContain("기능으");

66+

expect(keywords).toStrictEqual(["기능으로", "기능", "설명"]);

9367

});

94689569

it("keeps stripped ASCII stems for mixed Korean tokens", () => {

9670

const keywords = extractKeywords("API를 배포했다");

97-

expect(keywords).toContain("api");

98-

expect(keywords).toContain("배포했다");

71+

expect(keywords).toStrictEqual(["api를", "api", "배포했다"]);

9972

});

1007310174

it("handles mixed Korean and English query", () => {

@@ -129,18 +102,12 @@ describe("extractKeywords", () => {

129102130103

it("extracts keywords from Spanish conversational query", () => {

131104

const keywords = extractKeywords("ayer hablamos sobre la estrategia de despliegue");

132-

expect(keywords).toContain("estrategia");

133-

expect(keywords).toContain("despliegue");

134-

expect(keywords).not.toContain("ayer");

135-

expect(keywords).not.toContain("sobre");

105+

expect(keywords).toStrictEqual(["hablamos", "estrategia", "despliegue"]);

136106

});

137107138108

it("extracts keywords from Portuguese conversational query", () => {

139109

const keywords = extractKeywords("ontem falamos sobre a estratégia de implantação");

140-

expect(keywords).toContain("estratégia");

141-

expect(keywords).toContain("implantação");

142-

expect(keywords).not.toContain("ontem");

143-

expect(keywords).not.toContain("sobre");

110+

expect(keywords).toStrictEqual(["falamos", "estratégia", "implantação"]);

144111

});

145112146113

it("filters Spanish and Portuguese question stop words", () => {

@@ -155,10 +122,7 @@ describe("extractKeywords", () => {

155122156123

it("extracts keywords from Arabic conversational query", () => {

157124

const keywords = extractKeywords("بالأمس ناقشنا استراتيجية النشر");

158-

expect(keywords).toContain("ناقشنا");

159-

expect(keywords).toContain("استراتيجية");

160-

expect(keywords).toContain("النشر");

161-

expect(keywords).not.toContain("بالأمس");

125+

expect(keywords).toStrictEqual(["ناقشنا", "استراتيجية", "النشر"]);

162126

});

163127164128

it("filters Arabic question stop words", () => {

@@ -176,12 +140,12 @@ describe("extractKeywords", () => {

176140177141

it("handles query with only stop words", () => {

178142

const keywords = extractKeywords("the a an is are");

179-

expect(keywords.length).toBe(0);

143+

expect(keywords).toStrictEqual([]);

180144

});

181145182146

it("removes duplicate keywords", () => {

183147

const keywords = extractKeywords("test test testing");

184-

expect(countKeyword(keywords, "test")).toBe(1);

148+

expect(keywords).toStrictEqual(["test", "testing"]);

185149

});

186150187151

describe("with trigram tokenizer", () => {

@@ -233,21 +197,28 @@ describe("extractKeywords", () => {

233197

describe("expandQueryForFts", () => {

234198

it("returns original query and extracted keywords", () => {

235199

const result = expandQueryForFts("that API we discussed");

236-

expect(result.original).toBe("that API we discussed");

237-

expect(result.keywords).toContain("api");

238-

expect(result.keywords).toContain("discussed");

200+

expect(result).toStrictEqual({

201+

original: "that API we discussed",

202+

keywords: ["api", "discussed"],

203+

expanded: "that API we discussed OR api OR discussed",

204+

});

239205

});

240206241207

it("builds expanded OR query for FTS", () => {

242208

const result = expandQueryForFts("the solution for bugs");

243-

expect(result.expanded).toContain("OR");

244-

expect(result.expanded).toContain("solution");

245-

expect(result.expanded).toContain("bugs");

209+

expect(result).toStrictEqual({

210+

original: "the solution for bugs",

211+

keywords: ["solution", "bugs"],

212+

expanded: "the solution for bugs OR solution OR bugs",

213+

});

246214

});

247215248216

it("returns original query when no keywords extracted", () => {

249217

const result = expandQueryForFts("the");

250-

expect(result.keywords.length).toBe(0);

251-

expect(result.expanded).toBe("the");

218+

expect(result).toStrictEqual({

219+

original: "the",

220+

keywords: [],

221+

expanded: "the",

222+

});

252223

});

253224

});