@tencentcloud/sdk-mcp 1.7.2 → 1.7.3

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +13 -5
  3. package/knowledge/bm25.js +20 -11
  4. package/knowledge/search/generic-rerank.js +123 -0
  5. package/knowledge/search/search-pass.js +8 -1
  6. package/package.json +1 -1
  7. package/resource/_schema/query-normalization.yaml +6 -0
  8. package/resource/index/manifest.json +1 -1
  9. package/resource/integration/chat/preset/android/integration.md +33 -29
  10. package/resource/integration/chat/preset/flutter/integration.md +93 -92
  11. package/resource/knowledge/callkit/core-sdk/ios/offline-push.md +1 -1
  12. package/resource/knowledge/chat/best-practice/common/web-sdk-log-level.md +76 -0
  13. package/resource/knowledge/chat/best-practice/miniprogram/desktop-wechat-miniprogram-error.md +79 -0
  14. package/resource/knowledge/chat/best-practice/miniprogram/login-timeout-2801-diagnosis.md +1 -1
  15. package/resource/knowledge/chat/preset/android-view/integration.md +37 -29
  16. package/resource/knowledge/push/config/android/fcm.md +2 -6
  17. package/resource/knowledge/push/integration/android.md +777 -425
  18. package/resource/knowledge/push/integration/donut.md +54 -71
  19. package/resource/knowledge/push/integration/flutter.md +194 -63
  20. package/resource/knowledge/push/integration/harmonyos.md +7 -2
  21. package/resource/knowledge/push/integration/ios.md +23 -93
  22. package/resource/knowledge/push/integration/react-native.md +2 -1
  23. package/resource/knowledge/push/integration/uni-app.md +28 -106
  24. package/resource/knowledge/push/integration/unity.md +2 -1
  25. package/resource/knowledge/push/integration/unreal-engine.md +2 -1
  26. package/resource/knowledge/roomkit/best-practice/vue/screen-share-auto-stop-on-leave.md +62 -0
  27. package/resource/knowledge/roomkit/core-sdk/react/network-proxy.md +84 -0
  28. package/resource/knowledge/roomkit/core-sdk/vue/network-proxy.md +84 -0
  29. package/resource/knowledge/roomkit/core-sdk/vue/recording.md +245 -0
  30. package/resource/knowledge/roomkit/core-sdk/vue/whiteboard-annotation.md +196 -0
  31. package/resource/knowledge/roomkit/faq/error-code.md +103 -0
  32. package/resource/knowledge/roomkit/preset/harmonyos/integration.md +461 -0
  33. package/resource/knowledge/roomkit/preset/react/features/network-proxy.md +80 -0
  34. package/resource/knowledge/roomkit/preset/uniapp-app/integration.md +581 -0
  35. package/resource/knowledge/roomkit/preset/vue/features/ai-caption-translation.md +69 -0
  36. package/resource/knowledge/roomkit/preset/vue/features/ai-denoiser.md +67 -0
  37. package/resource/knowledge/roomkit/preset/vue/features/network-proxy.md +80 -0
  38. package/resource/knowledge/roomkit/preset/vue/features/recording.md +85 -0
  39. package/resource/knowledge/roomkit/preset/vue/features/whiteboard-annotation.md +86 -0
  40. package/server.js +1 -1
  41. package/utils/preflight-route.js +18 -6
  42. package/utils/report-cls-client.js +1 -1
  43. package/utils/report-es-client.js +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## Version 1.7.3 @2026.08.17
4
+
5
+ ### 新增
6
+ - 新增 RoomKit 多端集成、录制、白板、网络代理、AI 降噪与字幕翻译等知识库资源,扩充 Room 产品域知识覆盖。
7
+ - 新增错误码、日志级别、屏幕分享自动停止及微信小程序报错排查等最佳实践文档。
8
+ - 新增通用加性 rerank 模块,实现锚点选择与短语提取,并集成到搜索重排逻辑,提升召回排序准确率。
9
+
10
+ ### 变更
11
+ - 优化 BM25 索引为无原型对象,提升索引结构的隔离性与稳定性。
12
+
13
+ ### 修复
14
+ - 修复 BM25 打分受原型键污染导致的异常,增加原型键守卫,避免打分污染与 NaN 问题。
15
+
3
16
  ## Version 1.7.2 @2026.08.13
4
17
 
5
18
  ### 变更
package/README.md CHANGED
@@ -59,6 +59,19 @@ npx -y @tencentcloud/sdk-mcp
59
59
 
60
60
  > 仅展示最近更新,完整历史请查看 `CHANGELOG.md`。
61
61
 
62
+ ## Version 1.7.3 @2026.08.17
63
+
64
+ ### 新增
65
+ - 新增 RoomKit 多端集成、录制、白板、网络代理、AI 降噪与字幕翻译等知识库资源,扩充 Room 产品域知识覆盖。
66
+ - 新增错误码、日志级别、屏幕分享自动停止及微信小程序报错排查等最佳实践文档。
67
+ - 新增通用加性 rerank 模块,实现锚点选择与短语提取,并集成到搜索重排逻辑,提升召回排序准确率。
68
+
69
+ ### 变更
70
+ - 优化 BM25 索引为无原型对象,提升索引结构的隔离性与稳定性。
71
+
72
+ ### 修复
73
+ - 修复 BM25 打分受原型键污染导致的异常,增加原型键守卫,避免打分污染与 NaN 问题。
74
+
62
75
  ## Version 1.7.1 @2026.08.11
63
76
 
64
77
  ### 新增
@@ -82,8 +95,3 @@ npx -y @tencentcloud/sdk-mcp
82
95
 
83
96
  #### 修复
84
97
  - 修复复杂问法下部分检索结果偏题的问题,降低高分误召回概率。
85
-
86
- ### Version 1.6.6 @2026.07.18
87
-
88
- #### 新增
89
- - 支持 `get_native_live_uikit_integration` 工具,支持 LiveKit(Android/iOS) 含 UI 集成。
package/knowledge/bm25.js CHANGED
@@ -61,28 +61,29 @@ export function tokenize(text) {
61
61
  return tokens;
62
62
  }
63
63
  export function buildBM25Index(documents) {
64
- const postings = {};
65
- const docLengths = {};
66
- const docFreq = {};
64
+ // 用无原型对象,杜绝 term/id 为 'constructor'/'__proto__' 等原型键时的污染。
65
+ const postings = Object.create(null);
66
+ const docLengths = Object.create(null);
67
+ const docFreq = Object.create(null);
67
68
  let totalLength = 0;
68
69
  for (const doc of documents) {
69
70
  const tokens = tokenize(doc.text);
70
71
  docLengths[doc.id] = tokens.length;
71
72
  totalLength += tokens.length;
72
- const termFreq = {};
73
+ const termFreq = Object.create(null);
73
74
  for (const token of tokens) {
74
75
  termFreq[token] = (termFreq[token] ?? 0) + 1;
75
76
  }
76
77
  for (const [term, freq] of Object.entries(termFreq)) {
77
78
  if (!postings[term])
78
- postings[term] = {};
79
+ postings[term] = Object.create(null);
79
80
  postings[term][doc.id] = freq;
80
81
  docFreq[term] = (docFreq[term] ?? 0) + 1;
81
82
  }
82
83
  }
83
84
  const n = documents.length;
84
85
  const avgDocLength = n > 0 ? totalLength / n : 0;
85
- const idf = {};
86
+ const idf = Object.create(null);
86
87
  for (const [term, df] of Object.entries(docFreq)) {
87
88
  idf[term] = Math.log(1 + (n - df + 0.5) / (df + 0.5));
88
89
  }
@@ -96,15 +97,23 @@ export function buildBM25Index(documents) {
96
97
  }
97
98
  export function scoreBM25(query, chunkId, index) {
98
99
  const tokens = tokenize(query);
99
- const docLength = index.docLengths[chunkId] ?? 0;
100
- if (docLength === 0)
100
+ // Object.prototype 污染防护:postings/idf/docLengths 来自 JSON.parse 的普通对象,
101
+ // term 可能是 'constructor'/'toString'/'__proto__' 等原型键,直接 [] 取值会命中
102
+ // 原型链上的函数(如 Object.prototype.constructor),污染打分为 NaN。用 hasOwn 守卫。
103
+ const docLength = Object.hasOwn(index.docLengths, chunkId) ? index.docLengths[chunkId] : 0;
104
+ if (!docLength || Number.isNaN(docLength))
101
105
  return 0;
102
106
  let score = 0;
103
107
  for (const term of tokens) {
104
- const tf = index.postings[term]?.[chunkId] ?? 0;
105
- if (tf === 0)
108
+ if (!Object.hasOwn(index.postings, term) || !Object.hasOwn(index.idf, term))
109
+ continue;
110
+ const posting = index.postings[term];
111
+ const tf = Object.hasOwn(posting, chunkId) ? posting[chunkId] : 0;
112
+ if (!tf || Number.isNaN(tf))
113
+ continue;
114
+ const idf = index.idf[term];
115
+ if (Number.isNaN(idf))
106
116
  continue;
107
- const idf = index.idf[term] ?? 0;
108
117
  const numerator = tf * (K1 + 1);
109
118
  const denominator = tf + K1 * (1 - B + B * (docLength / (index.avgDocLength || 1)));
110
119
  score += idf * (numerator / denominator);
@@ -0,0 +1,123 @@
1
+ /**
2
+ * 通用加性 rerank:数据驱动的高 IDF 锚点命中 + 连续短语命中。
3
+ *
4
+ * 设计约束(零衰减 + 通用):
5
+ * - 纯加性:只往 boosts 加正数,无 penalty;无信号(无锚点且无短语命中)时返回空 map,
6
+ * 排序数学上完全等于现状 → 已有功能零衰减。
7
+ * - 量纲受控:单 chunk 上限 = W_ANCHOR + W_PHRASE,远低于 exact-lookup 的 +200~+300,
8
+ * 只在 BM25 平局区间起微调,不翻转既有精确命中。
9
+ * - 零硬编码:锚点门槛来自运行时 index.idf 分位、短语来自 query 结构,
10
+ * 不含任何具体词 / product / 文件名 → 对任意产品成立。
11
+ *
12
+ * 治两个诊断确认的真病根:
13
+ * - A(锚点命中):对抗「CJK unigram 被拆多份 × 高 tf 堆分」——稀有锚点命中给加权,
14
+ * 把靠通用词堆分的长文档区分开。
15
+ * - B(连续短语):用原始字符串连续匹配抓「组合稀有」(如 WebSocket is not a constructor),
16
+ * 同时天然排除 tokenize 产生的跨词垃圾 bigram(如「错怎」——它在原 query 里虽连续,
17
+ * 但作为连续串在无关文档正文中不命中,不会被误加分)。
18
+ */
19
+ // ── 超参(唯一可调项,均可回归验证)──────────────────────────────
20
+ /** 锚点门槛:取当前检索子库 IDF 分布的分位阈值,IDF ≥ 此值的 query term 视为锚点 */
21
+ const IDF_PERCENTILE = 0.75;
22
+ /** 锚点数上限,防止长 query 稀释权重 */
23
+ const MAX_ANCHORS = 6;
24
+ /** 锚点命中权重(与 BM25 top 分 20~50 同量级,低于 exact-lookup boost 量级) */
25
+ const W_ANCHOR = 40;
26
+ /** 连续短语命中权重 */
27
+ const W_PHRASE = 30;
28
+ /**
29
+ * 从 query term 中选出锚点:IDF ≥ 子库分位阈值的 term,按 IDF 降序取 top-K。
30
+ * 门槛完全由 index.idf 的运行时分布决定(数据驱动),不写死任何词。
31
+ */
32
+ function selectAnchors(queryTerms, index) {
33
+ const allIdf = Object.values(index.idf);
34
+ if (allIdf.length === 0)
35
+ return [];
36
+ const sorted = [...allIdf].sort((a, b) => a - b);
37
+ const threshold = sorted[Math.floor(sorted.length * IDF_PERCENTILE)] ?? 0;
38
+ const seen = new Set();
39
+ const anchors = [];
40
+ for (const term of queryTerms) {
41
+ if (seen.has(term))
42
+ continue;
43
+ seen.add(term);
44
+ // Object.prototype 污染防护:term 可能是 'constructor' 等原型键。
45
+ if (!Object.hasOwn(index.idf, term))
46
+ continue;
47
+ const idf = index.idf[term];
48
+ if (typeof idf !== 'number' || Number.isNaN(idf) || idf < threshold)
49
+ continue;
50
+ anchors.push({ term, idf });
51
+ }
52
+ anchors.sort((a, b) => b.idf - a.idf);
53
+ return anchors.slice(0, MAX_ANCHORS);
54
+ }
55
+ /**
56
+ * 从原始 query 抽取连续短语(不经 tokenize,避免分词假象):
57
+ * - 英文:相邻词对(连续两个 ≥2 长度的英文/数字 token)
58
+ * - 中文:连续 ≥2 字的中文片段(整段,不切分)
59
+ */
60
+ function extractPhrases(prompt) {
61
+ const phrases = [];
62
+ const enWords = prompt.toLowerCase().match(/[a-z0-9_]{2,}/g) ?? [];
63
+ for (let i = 0; i < enWords.length - 1; i += 1) {
64
+ phrases.push(`${enWords[i]} ${enWords[i + 1]}`);
65
+ }
66
+ for (const seg of prompt.match(/[\u4e00-\u9fff]{2,}/g) ?? []) {
67
+ phrases.push(seg);
68
+ }
69
+ return [...new Set(phrases)].filter((p) => p.replace(/\s/g, '').length >= 2);
70
+ }
71
+ /**
72
+ * 计算通用加性 boost。返回 chunkId -> 正分。
73
+ * 无锚点且无短语时返回空 map(排序退化为原始,零衰减)。
74
+ */
75
+ export function computeGenericAnchorBoosts(prompt, pool, index, tokenizeFn) {
76
+ const result = {};
77
+ const anchors = selectAnchors(tokenizeFn(prompt), index);
78
+ const phrases = extractPhrases(prompt);
79
+ // 门槛:既无锚点也无短语 → 直接返回空,排序完全等于原来。
80
+ if (anchors.length === 0 && phrases.length === 0)
81
+ return result;
82
+ const maxIdf = Math.max(1, ...anchors.map((a) => a.idf));
83
+ for (const chunk of pool) {
84
+ // ── 信号 A:命中锚点,按 IDF 归一化累加命中强度 ──
85
+ let anchorStrength = 0;
86
+ let anchorHits = 0;
87
+ for (const { term, idf } of anchors) {
88
+ // Object.prototype 污染防护:term 可能是 'constructor' 等原型键。
89
+ if (!Object.hasOwn(index.postings, term))
90
+ continue;
91
+ const posting = index.postings[term];
92
+ if ((Object.hasOwn(posting, chunk.id) ? posting[chunk.id] : 0) > 0) {
93
+ anchorStrength += idf / maxIdf;
94
+ anchorHits += 1;
95
+ }
96
+ }
97
+ // ── 信号 B:连续短语在 title / key_phrases / 正文原始串命中 ──
98
+ const haystack = [
99
+ chunk.title,
100
+ ...(chunk.key_phrases ?? []),
101
+ chunk.content,
102
+ ].filter(Boolean).join(' ').toLowerCase();
103
+ let phraseHits = 0;
104
+ for (const phrase of phrases) {
105
+ if (haystack.includes(phrase.toLowerCase())) {
106
+ phraseHits += 1;
107
+ }
108
+ }
109
+ // 该 chunk 无任何信号 → 不加分(保持原分)。
110
+ if (anchorHits === 0 && phraseHits === 0)
111
+ continue;
112
+ const boostA = anchors.length > 0
113
+ ? W_ANCHOR * (anchorStrength / anchors.length) // 归一化到 [0, W_ANCHOR]
114
+ : 0;
115
+ const boostB = phrases.length > 0
116
+ ? W_PHRASE * Math.min(1, phraseHits / phrases.length) // [0, W_PHRASE]
117
+ : 0;
118
+ const total = boostA + boostB;
119
+ if (total > 0)
120
+ result[chunk.id] = total;
121
+ }
122
+ return result;
123
+ }
@@ -1,9 +1,10 @@
1
1
  import { attachPoolContent } from '../content-loader.js';
2
2
  import { buildReferences } from '../doc-url-resolver.js';
3
- import { rankSubsetWithIndex } from '../bm25.js';
3
+ import { rankSubsetWithIndex, tokenize } from '../bm25.js';
4
4
  import { getProductsBM25Index } from '../bm25-cache.js';
5
5
  import { filterPool } from './filter-pool.js';
6
6
  import { runExactLookup } from './exact-lookup.js';
7
+ import { computeGenericAnchorBoosts } from './generic-rerank.js';
7
8
  import { applyRankMultipliers, computeApiNameCoverage, computeMissingApiTokens, isUrlMappingSource, postProcess, } from './search-core.js';
8
9
  function isBestPracticeSource(source) {
9
10
  return /\/best-practice\//i.test(source);
@@ -379,6 +380,12 @@ export function runSearchPass(params) {
379
380
  const productIndex = getProductsBM25Index(allChunks, passNorm.product);
380
381
  const poolWithContent = attachPoolContent(pool);
381
382
  const chunksById = new Map(poolWithContent.map((chunk) => [chunk.id, chunk]));
383
+ // 通用加性 rerank:数据驱动的高 IDF 锚点命中 + 连续短语命中。
384
+ // 纯加性、只加不减、无信号时返回空 map → 排序退化为原始,已有功能零衰减。
385
+ const genericBoosts = computeGenericAnchorBoosts(effectivePassNorm.prompt, poolWithContent, productIndex, tokenize);
386
+ for (const [id, amount] of Object.entries(genericBoosts)) {
387
+ boosts[id] = (boosts[id] ?? 0) + amount;
388
+ }
382
389
  const ranked = rankSubsetWithIndex(effectivePassNorm.prompt, pool.map((chunk) => chunk.id), productIndex, boosts);
383
390
  const rankedWithMultipliers = applyRankMultipliers(ranked, chunksById, {
384
391
  product: passNorm.product,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tencentcloud/sdk-mcp",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Tencent Cloud MCP Server for SDK",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -7,3 +7,9 @@ word:
7
7
  meeting: ["会议", "roomkit", "conference"]
8
8
  room: ["会议", "roomkit", "conference"]
9
9
  roomkit: ["会议", "roomkit", "conference"]
10
+ # 症状词 → 规范词:桌面版微信小程序运行 IM SDK 报 WebSocket is not a constructor / tencent_cloud_im_csig_flutter_for_web_25F_cy undefined。
11
+ # 用户常贴"AppService 逻辑层没有原生 WebSocket 构造函数"这类现象描述,与目标文档
12
+ # "桌面版微信 + 包名版本升级"词汇体系字面不重合,靠此映射补齐规范词,拉高召回重合度。
13
+ "WebSocket is not a constructor": ["桌面版微信", "小程序", "SDK 版本", "升级"]
14
+ AppService: ["桌面版微信", "小程序"]
15
+ "Cannot read properties of undefined (reading 'tencent_cloud_im_csig_flutter_for_web_25F_cy')": ["桌面版微信", "小程序", "SDK 版本"]