dsh-skill-folder 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  根治「DSH 每轮把全部技能 description 平铺进 prompt 吃 token」问题。
4
4
 
5
+ **v0.3.1(2026-08-30,路由收紧 + 稳定性)**:
6
+ - **routeHint 误路由修复**:多技能同时命中 → 不路由(「验证这个方案安全吗」不再同时猜 verifier+injection-guard);短消息(<5 字)不路由(「验证一下」「安全吗」是闲聊不是意图);名 token 改词边界匹配(`remem` 不再误命中 memory,完整 part 才命中)。普通对话的 `<skill-route>` 噪声大幅减少。
7
+ - 52 条测试全绿(新增 3 条误路由回归)。
8
+
5
9
  **v0.3.0(2026-08-30,语义混合 + 自动路由)**:
6
10
  - **语义检索腿**:`skill_search` 升级为 BM25 + 本地 bge-m3(Ollama)RRF 混合检索——中文意图可直接命中英文技能(BM25 词面鸿沟补上)。语义索引按内容指纹懒构建 + 落盘缓存(`~/.dsh/state/semantic-cache.json`),Ollama 离线/超时自动降级纯 BM25,绝不比旧版慢或差。
7
11
  - **自动路由提示**(`autoRoute`,默认开):用户消息明显指向某技能时(aliases 命中或技能名 token 命中),在**用户消息尾部**追加一行 `<skill-route>` 提示——用户区本就是动态区,catalog 前缀字节不变,KV 缓存零破坏。无关消息不路由,幂等,fail-safe。
@@ -121,6 +121,13 @@ export async function searchSkillsHybrid(pool, intent, cfg, topK, semIndex, semS
121
121
  * table in both directions (alias word in query → skill; query token in
122
122
  * skill name) plus a BM25 top hit as a second candidate — but only when the
123
123
  * top hit shares a surface token with the query (so "你好" never routes).
124
+ *
125
+ * v0.3.1 收紧(误路由修复):
126
+ * - 多技能同时命中 → null(意图不明不猜,避免「验证这个插件」同时路由
127
+ * verifier + cordis 两个方向);
128
+ * - 短消息(<5 字)不路由("验证一下"/"安全吗" 是闲聊不是意图);
129
+ * - 名 token 改为词边界匹配(技能名按 -_. 拆分的完整 part 全等,或
130
+ * part 以 token 开头且双方 ≥4 字符),"remem" 不再误命中 memory。
124
131
  * @param {Array<{name, description}>} pool - filtered searchable pool.
125
132
  * @param {string} userText - the latest user message text.
126
133
  * @param {object} cfg - merged config (aliases).
@@ -133,21 +140,32 @@ export function routeHint(pool, userText, cfg) {
133
140
  const names = new Set(pool.map((s) => s.name));
134
141
  const ql = q.toLowerCase();
135
142
 
136
- // Direct alias hit: any alias word appearing in the query.
143
+ // Alias stage: collect ALL distinct skills hit. Route only when exactly one
144
+ // skill is pointed at AND the message is long enough to carry intent.
145
+ const hitSkills = new Set();
137
146
  for (const [skill, words] of Object.entries(aliasMap)) {
138
147
  if (!names.has(skill) || !Array.isArray(words)) continue;
139
148
  for (const w of words) {
140
149
  const wl = String(w).toLowerCase().trim();
141
- if (wl.length >= 2 && ql.includes(wl)) return skill;
150
+ if (wl.length >= 2 && ql.includes(wl)) {
151
+ hitSkills.add(skill);
152
+ break;
153
+ }
142
154
  }
143
155
  }
156
+ if (hitSkills.size > 1) return null; // ambiguous — don't guess
157
+ if (hitSkills.size === 1) return q.length >= 5 ? [...hitSkills][0] : null;
144
158
 
145
- // Query token hits a skill name directly: token "memory" → "viking-memory-guide".
159
+ // Name-token stage: full-part match only (no substring guessing).
146
160
  const tokens = ql.match(/[a-z0-9][a-z0-9_+-]{1,}/g) || [];
147
161
  for (const t of tokens) {
148
162
  if (t.length < 3) continue;
149
163
  for (const s of pool) {
150
- if (s.name.toLowerCase().includes(t)) return s.name;
164
+ const parts = s.name.toLowerCase().split(/[-_.]/);
165
+ const hit = parts.some(
166
+ (p) => p === t || (p.length >= 4 && t.length >= 4 && p.startsWith(t)),
167
+ );
168
+ if (hit) return s.name;
151
169
  }
152
170
  }
153
171
 
package/package.json CHANGED
@@ -1,50 +1,50 @@
1
- {
2
- "name": "dsh-skill-folder",
3
- "version": "0.3.0",
4
- "description": "Fold the DSH skill catalog prompt surface: static KV-cache-stable catalog + BM25/bge-m3 hybrid skill_search + autoRoute hints. Rendering-only fold: source.entries stay untouched, the skill tool and /name injection stay host-owned. v0.3.0 adds a semantic retrieval leg (local Ollama bge-m3, RRF hybrid) and auto-route skill hints appended to the user message tail (KV-safe).",
5
- "keywords": [
6
- "dsh-plugin",
7
- "dsh",
8
- "deepseek-harness",
9
- "cordis",
10
- "skill",
11
- "skill-folder",
12
- "token-optimization",
13
- "bm25",
14
- "semantic-search",
15
- "kv-cache",
16
- "skill-search",
17
- "auto-route"
18
- ],
19
- "type": "module",
20
- "main": "lib/index.js",
21
- "exports": {
22
- ".": "./lib/index.js",
23
- "./lib/*": "./lib/*"
24
- },
25
- "files": [
26
- "lib",
27
- "docs",
28
- "cordis.patch.yml",
29
- "README.md"
30
- ],
31
- "dsh": {
32
- "bundle": {
33
- "patch": "./cordis.patch.yml"
34
- }
35
- },
36
- "license": "MIT",
37
- "engines": {
38
- "node": ">=18"
39
- },
40
- "scripts": {
41
- "test": "node --test \"test/*.test.js\""
42
- },
43
- "dependencies": {
44
- "@deepseek-ai/schemastery": "^3.18.1"
45
- },
46
- "peerDependencies": {
47
- "@deepseek-ai/cordis": "^4.0.1",
48
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.6"
49
- }
50
- }
1
+ {
2
+ "name": "dsh-skill-folder",
3
+ "version": "0.3.1",
4
+ "description": "Fold the DSH skill catalog prompt surface: static KV-cache-stable catalog + BM25/bge-m3 hybrid skill_search + autoRoute hints. Rendering-only fold: source.entries stay untouched, the skill tool and /name injection stay host-owned. v0.3.0 adds a semantic retrieval leg (local Ollama bge-m3, RRF hybrid) and auto-route skill hints appended to the user message tail (KV-safe).",
5
+ "keywords": [
6
+ "dsh-plugin",
7
+ "dsh",
8
+ "deepseek-harness",
9
+ "cordis",
10
+ "skill",
11
+ "skill-folder",
12
+ "token-optimization",
13
+ "bm25",
14
+ "semantic-search",
15
+ "kv-cache",
16
+ "skill-search",
17
+ "auto-route"
18
+ ],
19
+ "type": "module",
20
+ "main": "lib/index.js",
21
+ "exports": {
22
+ ".": "./lib/index.js",
23
+ "./lib/*": "./lib/*"
24
+ },
25
+ "files": [
26
+ "lib",
27
+ "docs",
28
+ "cordis.patch.yml",
29
+ "README.md"
30
+ ],
31
+ "dsh": {
32
+ "bundle": {
33
+ "patch": "./cordis.patch.yml"
34
+ }
35
+ },
36
+ "license": "MIT",
37
+ "engines": {
38
+ "node": "\u003e=18"
39
+ },
40
+ "scripts": {
41
+ "test": "node --test \"test/*.test.js\""
42
+ },
43
+ "dependencies": {
44
+ "@deepseek-ai/schemastery": "^3.18.1"
45
+ },
46
+ "peerDependencies": {
47
+ "@deepseek-ai/cordis": "^4.0.1",
48
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6"
49
+ }
50
+ }