@tencentcloud/sdk-mcp 1.6.5 → 1.6.7

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.
@@ -94,6 +94,19 @@ function loadFeatureAliases() {
94
94
  }
95
95
  return result;
96
96
  }
97
+ /**
98
+ * 将 prompt 按分隔符拆成子句列表,用于 url 行匹配。
99
+ * 分隔符:、 , , ; ; 空格
100
+ * 保留每个子句的原文(去首尾空白),不引入新词。
101
+ */
102
+ function splitPromptIntoClauses(prompt) {
103
+ const raw = prompt
104
+ .replace(/rest\s*api|服务端|server\s*api|api|怎么|如何|什么|用哪个|查询/g, '')
105
+ .replace(/\s+/g, ' ')
106
+ .trim();
107
+ const parts = raw.split(/[、,,;;、\s]+/).filter((p) => p.length >= 2);
108
+ return parts.length > 0 ? parts : [raw];
109
+ }
97
110
  const ROOM_CORE_SIGNAL = /atomicx\s*core|atomicxcore|atomicx|core\s*sdk|无\s*ui|自定义\s*ui|自实现|roomstore|store|useRoomState|useDeviceState|useLoginState/i;
98
111
  const ROOM_PRESET_SIGNAL = /预制|preset|roommainview|roommainwidget|默认\s*ui|主页面|房间主页面/i;
99
112
  const ROOM_FEATURE_SPECS = [
@@ -141,6 +154,7 @@ const LIVE_LIFECYCLE_APIS = ['createLive', 'endLive', 'joinLive', 'leaveLive'];
141
154
  export function runExactLookup(prompt, pool, norm) {
142
155
  const boosts = {};
143
156
  const exactHits = [];
157
+ const urlRowHitChunkIds = new Set();
144
158
  const lowerPrompt = prompt.toLowerCase();
145
159
  const addBoost = (chunk, amount, label) => {
146
160
  boosts[chunk.id] = (boosts[chunk.id] ?? 0) + amount;
@@ -303,57 +317,79 @@ export function runExactLookup(prompt, pool, norm) {
303
317
  }
304
318
  }
305
319
  }
306
- // E7: URL 映射表行级匹配(chunk.title = 子问题列;仅 boost 最佳行)
307
- const queryNorm = prompt
308
- .toLowerCase()
309
- .replace(/rest\s*api|服务端|server\s*api|api|怎么|如何|什么|用哪个|查询/g, '')
310
- .replace(/\s+/g, '');
311
- if (queryNorm.length >= 2) {
312
- const candidates = [];
313
- for (const chunk of pool) {
314
- if (!chunk.source.includes('knowledge/chat/urls/'))
315
- continue;
316
- const titleNorm = chunk.title.toLowerCase().replace(/\s+/g, '');
317
- if (!titleNorm)
320
+ // E7: URL 映射表行级匹配(chunk.title = 子问题列)
321
+ // 策略:保留整句匹配,同时补充子句拆分 + 逐行匹配,同一 chunk 取最高分。
322
+ // 子句拆分使 "创建群组、加入群组、发送群组自定义消息" 能命中多行。
323
+ const clauses = splitPromptIntoClauses(prompt.toLowerCase());
324
+ const candidates = [];
325
+ for (const chunk of pool) {
326
+ if (!chunk.source.includes('knowledge/chat/urls/'))
327
+ continue;
328
+ const titleNorm = chunk.title.toLowerCase().replace(/\s+/g, '');
329
+ if (!titleNorm)
330
+ continue;
331
+ // 对每个子句和整句分别打分,取最高分
332
+ let bestScore = 0;
333
+ const allParts = [...clauses, prompt.toLowerCase().replace(/\s+/g, '')];
334
+ // 也按常见分隔符拆分 title 得到 tokens,用于不连续匹配
335
+ const titleTokens = titleNorm.split(/[\/(((、,,\s]+/).filter(Boolean);
336
+ const seen = new Set();
337
+ for (const part of allParts) {
338
+ const pn = part.replace(/\s+/g, '');
339
+ if (pn.length < 2 || seen.has(pn))
318
340
  continue;
319
- let score = 0;
320
- if (queryNorm === titleNorm) {
321
- score = 1000;
341
+ seen.add(pn);
342
+ let s = 0;
343
+ if (pn === titleNorm) {
344
+ s = 1000;
322
345
  }
323
- else if (titleNorm.includes(queryNorm)) {
324
- const trailing = titleNorm.slice(titleNorm.indexOf(queryNorm) + queryNorm.length);
325
- score = 800 - trailing.length * 80;
346
+ else if (titleNorm.includes(pn)) {
347
+ const trailing = titleNorm.slice(titleNorm.indexOf(pn) + pn.length);
348
+ s = 800 - trailing.length * 80;
326
349
  }
327
- else if (queryNorm.includes(titleNorm)) {
328
- score = 700 + titleNorm.length;
350
+ else if (pn.includes(titleNorm)) {
351
+ s = 700 + titleNorm.length;
329
352
  }
330
- else {
331
- const queryLoose = queryNorm.replace(/发送/g, '发');
332
- if (queryLoose.length >= 3 && titleNorm.includes(queryLoose)) {
333
- score = 500;
334
- if (/批量|群组|群流|广播|导入|公众号|已读|回执/.test(titleNorm)
335
- && !/批量|群组|群|已读|回执/.test(queryNorm)) {
336
- score -= 250;
337
- }
338
- if (/^单发/.test(titleNorm) && /发送|单聊/.test(queryNorm)) {
339
- score += 120;
340
- }
341
- }
342
- }
343
- if (score > 0) {
344
- candidates.push({ chunk, score });
353
+ else if (titleTokens.some((token) => pn.includes(token) || token.includes(pn))) {
354
+ // 子句匹配 title 的 token(如 "创建群组" 匹配 "创建/解散群组(普通群管理)" 中的 "创建" token)
355
+ s = 600;
345
356
  }
357
+ if (s > bestScore)
358
+ bestScore = s;
346
359
  }
347
- candidates.sort((a, b) => b.score - a.score);
348
- const top = candidates[0];
349
- if (top) {
350
- addBoost(top.chunk, 200 + Math.min(top.score, 100), `E7:url-row:${top.chunk.title}`);
351
- const runnerUp = candidates[1];
352
- if (runnerUp && top.score - runnerUp.score <= 20) {
353
- addBoost(runnerUp.chunk, 150 + Math.min(runnerUp.score, 80), `E7:url-row:${runnerUp.chunk.title}`);
360
+ if (bestScore <= 0) {
361
+ // 退化:子句无匹配时,试 loose(去噪声字 + 单字容错)
362
+ const qn = clauses[0].replace(/发送/g, '发');
363
+ if (qn.length >= 3 && titleNorm.includes(qn)) {
364
+ bestScore = 500;
365
+ if (/批量|群组|群流|广播|导入|公众号|已读|回执/.test(titleNorm)
366
+ && !/批量|群组|群|已读|回执/.test(clauses[0])) {
367
+ bestScore -= 250;
368
+ }
369
+ if (/^单发/.test(titleNorm) && /发送|单聊/.test(clauses[0])) {
370
+ bestScore += 120;
371
+ }
354
372
  }
355
373
  }
374
+ if (bestScore > 0) {
375
+ candidates.push({ chunk, score: bestScore });
376
+ }
356
377
  }
378
+ candidates.sort((a, b) => b.score - a.score);
379
+ const strongCandidates = candidates
380
+ .filter(({ score }) => score >= 500)
381
+ .slice(0, 12);
382
+ strongCandidates.forEach(({ chunk, score }, idx) => {
383
+ // 递减 boost:前两条更高,其余保持可召回但不过度压制 BM25
384
+ // token 匹配(600 分)至少给 150,确保子句拆分的行不被 BM25 原始分压掉
385
+ const amount = idx === 0
386
+ ? 200 + Math.min(score, 100)
387
+ : idx === 1
388
+ ? 170 + Math.min(score, 90)
389
+ : Math.max(score >= 600 ? 150 : 90, 140 - idx * 8);
390
+ addBoost(chunk, amount, `E7:url-row:${chunk.title}`);
391
+ urlRowHitChunkIds.add(chunk.id);
392
+ });
357
393
  }
358
394
  // E8: 集成查阅意图 boost——prompt 含集成/接入/快速开始/接入文档等意图词时,
359
395
  // 把 {integration|knowledge}/{product}/preset/{fw}/integration.md 系列文件顶到前列。
@@ -492,5 +528,5 @@ export function runExactLookup(prompt, pool, norm) {
492
528
  }
493
529
  }
494
530
  }
495
- return { boosts, exactHits };
531
+ return { boosts, exactHits, urlRowHitChunkIds: [...urlRowHitChunkIds] };
496
532
  }
@@ -23,7 +23,7 @@ function loadManifest() {
23
23
  cachedManifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
24
24
  return cachedManifest;
25
25
  }
26
- function postProcess(ranked, chunksById, limit) {
26
+ function postProcess(ranked, chunksById, limit, opts) {
27
27
  const sourceCount = {};
28
28
  const urlMappingSourceCount = {};
29
29
  /** 已入选的 push config/android/{vendor} 文件,用于抑制其他厂商噪声 */
@@ -34,9 +34,10 @@ function postProcess(ranked, chunksById, limit) {
34
34
  if (!chunk)
35
35
  continue;
36
36
  const isUrlMapping = Boolean(isUrlMappingSource(chunk.source));
37
+ const isPinnedUrlRow = isUrlMapping && (opts?.pinnedUrlRowChunkIds?.has(chunk.id) ?? false);
37
38
  if (isUrlMapping) {
38
39
  const urlCount = urlMappingSourceCount[chunk.source] ?? 0;
39
- if (urlCount >= 1)
40
+ if (!isPinnedUrlRow && urlCount >= 1)
40
41
  continue;
41
42
  urlMappingSourceCount[chunk.source] = urlCount + 1;
42
43
  }
@@ -68,8 +69,9 @@ function postProcess(ranked, chunksById, limit) {
68
69
  if (firstPush) {
69
70
  // 首条不设分数截止,至少保证 1 条返回
70
71
  }
71
- else {
72
+ else if (!isPinnedUrlRow) {
72
73
  // 分数衰减到 top 的 5% 以下时停止,不硬填到 limit
74
+ // chat/urls 的行级精确命中(E7)不受该规则截断,保证多子主题可并行返回
73
75
  const topScore = fragments[0].score;
74
76
  if (topScore > 0 && item.score < topScore * 0.05)
75
77
  break;
@@ -311,7 +313,7 @@ export function searchKnowledge(params) {
311
313
  if (pool.length === 0 && passNorm.types?.length) {
312
314
  pool = filterPool(allChunks, { ...passNorm, types: undefined });
313
315
  }
314
- const { boosts, exactHits } = runExactLookup(passNorm.prompt, pool, passNorm);
316
+ const { boosts, exactHits, urlRowHitChunkIds } = runExactLookup(passNorm.prompt, pool, passNorm);
315
317
  // A2 补充正向路由:UserSig 问法下允许 share 命中且优先于无关 urls 噪声
316
318
  if (/usersig|sdkappid|secretkey|鉴权|签名|gentestusersig/i.test(passNorm.prompt)) {
317
319
  for (const chunk of pool) {
@@ -337,7 +339,10 @@ export function searchKnowledge(params) {
337
339
  framework: passNorm.framework,
338
340
  frameworks: passNorm.frameworks,
339
341
  });
340
- const fragments = postProcess(rankedWithMultipliers, chunksById, passNorm.limit);
342
+ const pinnedUrlRowChunkIds = new Set(urlRowHitChunkIds);
343
+ const fragments = postProcess(rankedWithMultipliers, chunksById, passNorm.limit, {
344
+ pinnedUrlRowChunkIds,
345
+ });
341
346
  const urlMappingSources = [...new Set(fragments.map((f) => f.source).filter((source) => isUrlMappingSource(source)))];
342
347
  const references = buildReferences(fragments);
343
348
  const apiNameCoverage = computeApiNameCoverage(queryApiTokens, poolWithContent);
@@ -350,6 +355,8 @@ export function searchKnowledge(params) {
350
355
  references,
351
356
  apiNameCoverage,
352
357
  missingApiTokens,
358
+ urlMapRelaxed: pinnedUrlRowChunkIds.size > 0,
359
+ urlMapExactHitCount: pinnedUrlRowChunkIds.size,
353
360
  };
354
361
  };
355
362
  let pass = runSearchPass(norm);
@@ -389,6 +396,8 @@ export function searchKnowledge(params) {
389
396
  filtered_size: pass.pool.length,
390
397
  exact_hits: pass.exactHits,
391
398
  ...(pass.urlMappingSources.length ? { url_mapping_sources: pass.urlMappingSources } : {}),
399
+ ...(pass.urlMapRelaxed ? { url_map_relaxed: pass.urlMapRelaxed } : {}),
400
+ ...(pass.urlMapExactHitCount > 0 ? { url_map_exact_hit_count: pass.urlMapExactHitCount } : {}),
392
401
  ...(pass.references.length ? { references: pass.references } : {}),
393
402
  ...(topScore !== undefined ? { top_score: Number(topScore.toFixed(2)) } : {}),
394
403
  ...(secondScore !== undefined ? { second_score: Number(secondScore.toFixed(2)) } : {}),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tencentcloud/sdk-mcp",
3
- "version": "1.6.5",
3
+ "version": "1.6.7",
4
4
  "description": "Tencent Cloud MCP Server for SDK",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -0,0 +1 @@
1
+ {"chat-setting":["chat-setting","chatsetting","chat_setting"],"contact-list":["contact-list","contactlist","contact_list"],"conversation-actions":["conversation-actions","conversationactions","conversation_actions"],"conversation-list":["conversation-list","conversationlist","conversation_list"],"conversation-preview":["conversation-preview","conversationpreview","conversation_preview"],"conversation-search":["conversation-search","conversationsearch","conversation_search"],"message-input":["message-input","messageinput","message_input"],"message-list":["message-list","messagelist","message_list"],"search":["search","search","search"],"theme":["theme","theme","theme"],"chat-header":["chat-header","chatheader","chat_header"]}
@@ -0,0 +1 @@
1
+ {"knowledge/rtcengine/web/how_to_run_web_sdk_demo.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-10-basic-get-started-with-demo.md","knowledge/rtcengine/web/plugin/20-advanced-customized-capture-rendering.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-20-advanced-customized-capture-rendering.md","knowledge/rtcengine/web/plugin/21-advanced-auto-play-policy.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-21-advanced-auto-play-policy.md","knowledge/rtcengine/web/plugin/22-advanced-audio-mixer.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-22-advanced-audio-mixer.md","knowledge/rtcengine/web/plugin/23-advanced-support-detection.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-23-advanced-support-detection.md","knowledge/rtcengine/web/plugin/24-advanced-network-quality.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-24-advanced-network-quality.md","knowledge/rtcengine/web/plugin/25-advanced-device-change.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-25-advanced-device-change.md","knowledge/rtcengine/web/plugin/26-advanced-publish-cdn-stream.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-26-advanced-publish-cdn-stream.md","knowledge/rtcengine/web/plugin/27-advanced-small-stream.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-27-advanced-small-stream.md","knowledge/rtcengine/web/plugin/28-advanced-beauty.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-28-advanced-beauty.md","knowledge/rtcengine/web/plugin/29-advanced-water-mark.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-29-advanced-water-mark.md","knowledge/rtcengine/web/plugin/30-advanced-cross-room-link.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-30-advanced-cross-room-link.md","knowledge/rtcengine/web/plugin/31-advanced-plugins-overview.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-31-advanced-plugins-overview.md","knowledge/rtcengine/web/plugin/34-advanced-proxy.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-34-advanced-proxy.md","knowledge/rtcengine/web/plugin/35-advanced-ai-denoiser.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-35-advanced-ai-denoiser.md","knowledge/rtcengine/web/plugin/36-advanced-virtual-background.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-36-advanced-virtual-background.md","knowledge/rtcengine/web/plugin/37-advanced-voice-changer.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-37-advanced-voice-changer.md","knowledge/rtcengine/web/plugin/38-advanced-basic-beauty.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-38-advanced-basic-beauty.md","knowledge/rtcengine/web/plugin/39-advanced-video-decoder.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-39-advanced-video-decoder.md","knowledge/rtcengine/web/plugin/40-advanced-video-mixer.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-40-advanced-video-mixer.md","knowledge/rtcengine/web/plugin/41-advanced-small-stream-auto-switcher.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-41-advanced-small-stream-auto-switcher.md","knowledge/rtcengine/web/plugin/42-advanced-realtime-transcriber.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-42-advanced-realtime-transcriber.md","knowledge/rtcengine/web/plugin/43-advanced-face-detection.md":"https://web.sdk.qcloud.com/trtc/webrtc/doc/zh-cn/tutorial-43-advanced-face-detection.md"}