@tencent-rtc/mcp 1.7.0 → 1.7.2
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/CHANGELOG.md +16 -0
- package/README.md +11 -6
- package/knowledge/doc-url-resolver.js +43 -16
- package/knowledge/search/exact-lookup.js +117 -18
- package/knowledge/search/intent-router.js +21 -5
- package/knowledge/search/l1-enrich.js +159 -0
- package/knowledge/search/query-normalizer.js +8 -1
- package/knowledge/search/search-core.js +25 -6
- package/knowledge/search/search-knowledge.js +159 -46
- package/knowledge/search/search-message.js +13 -12
- package/knowledge/search/url-row-idf.js +120 -0
- package/knowledge/search/url-row-scorer.js +306 -227
- package/package.json +3 -1
- package/resource/index/manifest.json +1 -1
- package/resource/knowledge/chat/urls/product.md +17 -16
- package/resource/knowledge/chat/urls/restapi.md +3 -2
- package/resource/knowledge/chat/urls/sdk/android.md +6 -5
- package/resource/knowledge/chat/urls/sdk/flutter.md +6 -5
- package/resource/knowledge/chat/urls/sdk/ios.md +4 -3
- package/resource/knowledge/chat/urls/sdk/web.md +6 -5
- package/resource/knowledge/chat/urls/webhook.md +0 -5
- package/server.js +4 -4
- package/streamable-http.js +19 -54
- package/tools/common/finalize_answer.js +1 -9
- package/tools/common/search_trtc_knowledge.js +25 -11
- package/tools/definitions/finalize_answer_def.js +2 -2
- package/tools/definitions/search_trtc_knowledge_def.js +4 -2
- package/utils/fetch-doc-content.js +198 -0
- package/utils/preflight-route.js +197 -0
- package/utils/report-cls-client.js +1 -1
- package/utils/report-es-client.js +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// ========== 信号分层(方案 §3,中英双语) ==========
|
|
2
|
+
// 产品词:产品线路标识
|
|
3
|
+
const PRODUCT_SIGNALS = {
|
|
4
|
+
call: /CallKit|TUICallKit|TUICallEngine|语音通话|视频通话|来电|去电|拨打|\b(?:voice|video)\s+calls?\b|incoming\s+calls?|outgoing\s+calls?|make\s+a\s+call|\bdial(?:ing)?\b/i,
|
|
5
|
+
live: /LiveKit|TUILiveKit|直播|语聊房|连麦|开播|观看直播|\blive\s+stream(?:ing)?\b|\bvoice\s+room\b|co-?host(?:ing)?|go\s+live|start\s+stream(?:ing)?|watch(?:ing)?\s+live|\bbroadcast(?:ing)?\b/i,
|
|
6
|
+
room: /RoomKit|会议|会中|会议室|屏幕分享|白板|\bconference\b|\bmeetings?\b|in-?meeting|meeting\s+room|screen\s+shar(?:e|ing)|white\s*board/i,
|
|
7
|
+
chat: /\bchat\b|\bim\b|会话|消息|TUIKit|ChatKit|\bconversation\b|\bmessaging\b|\binstant\s+messaging\b/i,
|
|
8
|
+
push: /TIMPush|推送|离线推送|FCM|APNs|华为|小米|OPPO|vivo|\bpush(?:\s+notification)?s?\b|offline\s+push|vendor\s+channel|\bHuawei\b|\bXiaomi\b|\bHonor\b/i,
|
|
9
|
+
};
|
|
10
|
+
// 平台词(纯运行形态,不含任何产品词)
|
|
11
|
+
const PLATFORM_NATIVE_SIGNAL = /\b(android|ios|flutter|c\+\+|native)\b|安卓\s*(sdk|端|原生)|iOS\s*(SDK|端|原生)|原生\s*(sdk|端)?|native\s+(?:sdk|client|app)|mobile\s+(?:sdk|native)/i;
|
|
12
|
+
const PLATFORM_WEB_SIGNAL = /\b(web|h5|html5|browser|webview)\b|浏览器|网页|Web端|H5端|网页端|web\s+(?:app|client|page)|in-?browser|mobile\s+browser|安卓\s*(浏览器|网页|H5|Web|webview)|iOS\s*(浏览器|网页|H5|Web|webview)|Android\s*(?:浏览器|网页|H5|Web|webview|browser|web)|iPad\s*(?:浏览器|网页|H5|Web|browser|web)|\b(Safari|Chrome|Edge|UC|QQ浏览器|QQ\s+Browser)\b/i;
|
|
13
|
+
// 平台+产品复合词(运行形态 + 产品线路标识)
|
|
14
|
+
const WEB_PRODUCT_PAIR_SIGNAL = /\bweb\s+(trtc|sdk|im|chat|roomkit)\b|\b(trtc|sdk|im|chat|roomkit)\s+web\b|trtc[-\s]?sdk|trtc\.js/i;
|
|
15
|
+
// API 词(客户端调用形态)
|
|
16
|
+
const NATIVE_TRTC_CLASS_SIGNAL = /\b(TRTCCloud|TRTCCloudListener|TRTCCloudDelegate|ITRTCCloud|TRTCTypeDef|TRTCCloudCallback|TXAudioEffectManager|TXBeautyManager|TXDeviceManager|TXLiteAVCode|TXLiveSDKTypeDef)\b/i;
|
|
17
|
+
const NATIVE_TRTC_METHOD_SIGNAL = /\b(?:TRTCCloud|ITRTCCloud|TX[A-Za-z0-9_]+)\s*(?:\.|::|->)\s*(?:set|get|start|stop|enable|disable)[A-Z][A-Za-z0-9_]+\b/i;
|
|
18
|
+
const WEB_TRTC_API_RE = /TRTC\.(setCurrentSpeaker|getMicrophoneList|getSpeakerList|getCameraList|isSupported|create)|trtc\.(startLocalAudio|startLocalVideo|updateLocalAudio|updateLocalVideo)/i;
|
|
19
|
+
const WEB_TRTC_TOKEN_RE = /^TRTC\.(setCurrentSpeaker|getMicrophoneList|getSpeakerList|getCameraList|isSupported|create)$/i;
|
|
20
|
+
// 协议级 TRTC 信号
|
|
21
|
+
const TRTC_SIGNAL = /\bTRTC\b|\bWebRTC\b|rtcengine|TRTCCloud|腾讯实时音视频/i;
|
|
22
|
+
// ========== 工具函数 ==========
|
|
23
|
+
function uniq(list) {
|
|
24
|
+
return [...new Set(list)];
|
|
25
|
+
}
|
|
26
|
+
function extractQueryApiTokens(prompt) {
|
|
27
|
+
const matches = prompt.match(/\b(?:TRTC|trtc)\.[A-Za-z_][A-Za-z0-9_]*\b/g) ?? [];
|
|
28
|
+
return uniq(matches.map((m) => m.replace(/^trtc\./i, 'TRTC.')));
|
|
29
|
+
}
|
|
30
|
+
function collectPromptSignals(prompt) {
|
|
31
|
+
const products = new Set();
|
|
32
|
+
if (PRODUCT_SIGNALS.call.test(prompt))
|
|
33
|
+
products.add('call');
|
|
34
|
+
if (PRODUCT_SIGNALS.live.test(prompt))
|
|
35
|
+
products.add('live');
|
|
36
|
+
if (PRODUCT_SIGNALS.room.test(prompt))
|
|
37
|
+
products.add('room');
|
|
38
|
+
if (PRODUCT_SIGNALS.chat.test(prompt))
|
|
39
|
+
products.add('chat');
|
|
40
|
+
if (PRODUCT_SIGNALS.push.test(prompt))
|
|
41
|
+
products.add('push');
|
|
42
|
+
if (TRTC_SIGNAL.test(prompt))
|
|
43
|
+
products.add('trtc');
|
|
44
|
+
// 平台 tokens:web signal 锁定 → 压制 native 单字(安卓/iOS 仅归 hostEnv);
|
|
45
|
+
// 真复合词(unreal/unity/harmonyos/react-native/flutter/c++)不受影响。
|
|
46
|
+
const platforms = [];
|
|
47
|
+
const webLocked = PLATFORM_WEB_SIGNAL.test(prompt) || WEB_PRODUCT_PAIR_SIGNAL.test(prompt);
|
|
48
|
+
if (webLocked) {
|
|
49
|
+
platforms.push('web');
|
|
50
|
+
}
|
|
51
|
+
const nativeSpecificHits = [];
|
|
52
|
+
if (/\b(?:unreal|UE[45]?|unreal-engine)\b/i.test(prompt))
|
|
53
|
+
nativeSpecificHits.push('unreal-engine');
|
|
54
|
+
if (/\b(?:unity)\b/i.test(prompt))
|
|
55
|
+
nativeSpecificHits.push('unity');
|
|
56
|
+
if (/\b(?:harmonyos|鸿蒙|HarmonyOS)\b/i.test(prompt))
|
|
57
|
+
nativeSpecificHits.push('harmonyos');
|
|
58
|
+
if (/\b(?:react-native)\b/i.test(prompt))
|
|
59
|
+
nativeSpecificHits.push('react-native');
|
|
60
|
+
if (/\b(?:flutter)\b/i.test(prompt))
|
|
61
|
+
nativeSpecificHits.push('flutter');
|
|
62
|
+
if (/\b(?:c\+\+)\b/i.test(prompt))
|
|
63
|
+
nativeSpecificHits.push('c++');
|
|
64
|
+
// 安卓/iOS 单字只在非 web-locked 时进 platforms(web-locked 时仅归 hostEnv)
|
|
65
|
+
if (!webLocked && /\b(?:ios|iphone|ipad|苹果)\b/i.test(prompt))
|
|
66
|
+
nativeSpecificHits.push('ios');
|
|
67
|
+
if (!webLocked && /\b(?:android|安卓)\b/i.test(prompt))
|
|
68
|
+
nativeSpecificHits.push('android');
|
|
69
|
+
// 真复合词(如 unity/unreal/flutter/harmonyos/react-native/c++)无条件 push;单字在 webLocked 时被压制
|
|
70
|
+
if (nativeSpecificHits.length > 0) {
|
|
71
|
+
platforms.push(...nativeSpecificHits);
|
|
72
|
+
}
|
|
73
|
+
else if (!webLocked && PLATFORM_NATIVE_SIGNAL.test(prompt)) {
|
|
74
|
+
// 仅 "native" 词,未指定细分 → 默认 android(webLocked 时不触发 fallback,避免被 \b(android|ios|...) 反向命中把 web 路径覆盖成 native)
|
|
75
|
+
platforms.push('android');
|
|
76
|
+
}
|
|
77
|
+
// Host env:仅用于标记,不进 platforms 归一化
|
|
78
|
+
let hostEnv = null;
|
|
79
|
+
if (/\bios\b|iphone|ipad|苹果/i.test(prompt))
|
|
80
|
+
hostEnv = 'ios';
|
|
81
|
+
else if (/\bandroid\b|安卓/i.test(prompt))
|
|
82
|
+
hostEnv = 'android';
|
|
83
|
+
const queryApiTokens = extractQueryApiTokens(prompt);
|
|
84
|
+
const hasWebTrtcApi = PLATFORM_WEB_SIGNAL.test(prompt)
|
|
85
|
+
|| WEB_TRTC_API_RE.test(prompt)
|
|
86
|
+
|| queryApiTokens.some((t) => WEB_TRTC_TOKEN_RE.test(t));
|
|
87
|
+
const hasNativeTrtcApi = NATIVE_TRTC_CLASS_SIGNAL.test(prompt) || NATIVE_TRTC_METHOD_SIGNAL.test(prompt);
|
|
88
|
+
return { products, platforms, hostEnv, hasWebTrtcApi, hasNativeTrtcApi, queryApiTokens };
|
|
89
|
+
}
|
|
90
|
+
function reconcileWithPrompt(promptValues, explicit) {
|
|
91
|
+
// 核心规则:prompt 是真值源,explicit 只在 prompt 为空时启用。
|
|
92
|
+
// 这条规则必须严格遵守——
|
|
93
|
+
// 「prompt 是用户问题表达出来的真实意图」,explicit 只在外部上下文(IDE/文件/历史)有补充价值,
|
|
94
|
+
// 但 prompt 既然明示了「Web」,就要按 Web 来,不要因为 explicit 多了 'android' 就把它"补"进来当成双路。
|
|
95
|
+
// 情形 1:prompt 真值存在 → 信任 prompt 真值
|
|
96
|
+
// - 即便 explicit 扩张(prompt 外多列了平台)→ 也只输出 prompt 真值(prompt_override=true 表示 agent 推理被忽略)
|
|
97
|
+
// - 即便 explicit 收缩(prompt 真值的子集)→ 也只输出 prompt 真值(避免丢失用户意图)
|
|
98
|
+
if (promptValues.length > 0) {
|
|
99
|
+
const promptSet = new Set(promptValues);
|
|
100
|
+
const sameAsExplicit = !!explicit?.length
|
|
101
|
+
&& explicit.length === promptValues.length
|
|
102
|
+
&& explicit.every((v) => promptSet.has(v));
|
|
103
|
+
return { values: uniq(promptValues), corrected: !sameAsExplicit };
|
|
104
|
+
}
|
|
105
|
+
// 情形 2:prompt 真值无平台信息 → 信任上游 agent 基于上下文(IDE/文件/历史)的推理
|
|
106
|
+
if (!promptValues.length) {
|
|
107
|
+
return { values: uniq(explicit ?? []), corrected: false };
|
|
108
|
+
}
|
|
109
|
+
return { values: [], corrected: false };
|
|
110
|
+
}
|
|
111
|
+
// ========== Phase 3: 单 SearchParams 构造 ==========
|
|
112
|
+
//
|
|
113
|
+
// 关键约束:**永远只返回单 primary**,consumer 只跑一次 searchKnowledge。
|
|
114
|
+
// multi-platform / multi-product 通过把 frameworks / product 设成数组交给 search core 处理。
|
|
115
|
+
// search core 的 filterPool.applyRankMultipliers 已原生支持多值归并。
|
|
116
|
+
function passthroughPlan(params, reason, env) {
|
|
117
|
+
return { primary: params, meta: { route_reason: reason, environment_downgraded: env } };
|
|
118
|
+
}
|
|
119
|
+
/** 单产品路径:product 是单值;frameworks 是数组(可能多平台共享一个 product) */
|
|
120
|
+
function singleProductPlan(params, product, frameworks, hostEnv, reason) {
|
|
121
|
+
const envDiff = hostEnv != null && !frameworks.includes(hostEnv);
|
|
122
|
+
return {
|
|
123
|
+
primary: { ...params, product: [product], frameworks },
|
|
124
|
+
meta: { route_reason: reason, environment_downgraded: envDiff },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** TRC 路径:product 是数组(rtcengine/native_trtc_sdk 两个产品码,按 platforms 各命中其一);frameworks 也是数组 */
|
|
128
|
+
function trcMultiProductPlan(params, products, frameworks, reason, env) {
|
|
129
|
+
return {
|
|
130
|
+
primary: { ...params, product: products, frameworks },
|
|
131
|
+
meta: { route_reason: reason, environment_downgraded: env },
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ========== 主入口(基于 prompt 真值归一化) ==========
|
|
135
|
+
export function preflightRoute(params) {
|
|
136
|
+
const prompt = params.prompt ?? '';
|
|
137
|
+
const explicitFrameworks = params.frameworks?.length ? uniq(params.frameworks) : undefined;
|
|
138
|
+
const explicitProducts = params.product?.length ? uniq(params.product) : undefined;
|
|
139
|
+
// Phase 1
|
|
140
|
+
const signals = collectPromptSignals(prompt);
|
|
141
|
+
// —— 真跨主题(多产品信号)直接 passthrough
|
|
142
|
+
const nonTrtcProducts = [...signals.products].filter((p) => p !== 'trtc');
|
|
143
|
+
if (nonTrtcProducts.length > 1) {
|
|
144
|
+
return passthroughPlan(params, 'cross_product_passthrough', false);
|
|
145
|
+
}
|
|
146
|
+
// Phase 2: frameworks 调和
|
|
147
|
+
const fwRecon = reconcileWithPrompt(signals.platforms, explicitFrameworks);
|
|
148
|
+
const frameworks = fwRecon.values;
|
|
149
|
+
const envDowngraded = signals.hostEnv != null && !frameworks.includes(signals.hostEnv);
|
|
150
|
+
// Phase 2.5: products 调和(仅当 prompt 有非 TRTC 单产品时取此产品;TRTC 由 platform 推断 rtcengine/native_trtc_sdk)
|
|
151
|
+
const explicitTrtcBoth = explicitProducts?.includes('rtcengine') && explicitProducts?.includes('native_trtc_sdk');
|
|
152
|
+
const explicitTrtcAny = explicitProducts?.some((p) => p === 'rtcengine' || p === 'native_trtc_sdk') ?? false;
|
|
153
|
+
const isTrtcFamily = signals.products.has('trtc') || explicitTrtcBoth || (explicitTrtcAny && !nonTrtcProducts[0]);
|
|
154
|
+
// —— TRTC 家族:产物随平台分流
|
|
155
|
+
if (isTrtcFamily) {
|
|
156
|
+
const hasWeb = frameworks.includes('web');
|
|
157
|
+
const natives = frameworks.filter((f) => f !== 'web');
|
|
158
|
+
// TRTC + 多平台(web + native)→ product 数组,search core filterPool 原生接受多 product 交集
|
|
159
|
+
if (hasWeb && natives.length > 0) {
|
|
160
|
+
const reason = fwRecon.corrected ? 'trtc_multi_platform_prompt_override' : 'trtc_multi_platform';
|
|
161
|
+
return trcMultiProductPlan(params, ['rtcengine', 'native_trtc_sdk'], frameworks, reason, envDowngraded);
|
|
162
|
+
}
|
|
163
|
+
// TRTC + 仅 web
|
|
164
|
+
if (hasWeb) {
|
|
165
|
+
const reason = fwRecon.corrected ? 'trtc_web_prompt_override' : 'trtc_web';
|
|
166
|
+
return singleProductPlan(params, 'rtcengine', ['web'], signals.hostEnv, reason);
|
|
167
|
+
}
|
|
168
|
+
// TRTC + 仅 native
|
|
169
|
+
if (natives.length > 0) {
|
|
170
|
+
const reason = fwRecon.corrected ? 'trtc_native_prompt_override' : 'trtc_native';
|
|
171
|
+
return singleProductPlan(params, 'native_trtc_sdk', natives, signals.hostEnv, reason);
|
|
172
|
+
}
|
|
173
|
+
// TRTC 但 prompt / explicit 都没有可用平台 → 透传
|
|
174
|
+
return passthroughPlan(params, 'trtc_no_platform_resolved', false);
|
|
175
|
+
}
|
|
176
|
+
// —— 单非 TRTC 产品
|
|
177
|
+
if (nonTrtcProducts.length === 1) {
|
|
178
|
+
const product = nonTrtcProducts[0];
|
|
179
|
+
// 多平台 → product 单值,frameworks 多值(search core filterPool 原生按 framework 交集过滤)
|
|
180
|
+
if (frameworks.length >= 2) {
|
|
181
|
+
const reason = fwRecon.corrected ? 'multi_platform_prompt_override' : 'multi_platform';
|
|
182
|
+
return singleProductPlan(params, product, frameworks, signals.hostEnv, reason);
|
|
183
|
+
}
|
|
184
|
+
// 单平台
|
|
185
|
+
if (frameworks.length === 1) {
|
|
186
|
+
const reason = fwRecon.corrected ? 'single_platform_prompt_override' : 'single_platform';
|
|
187
|
+
return singleProductPlan(params, product, frameworks, signals.hostEnv, reason);
|
|
188
|
+
}
|
|
189
|
+
// 无平台信号:透传(保留 explicit frameworks)
|
|
190
|
+
if (explicitFrameworks?.length) {
|
|
191
|
+
return singleProductPlan(params, product, uniq(explicitFrameworks), signals.hostEnv, 'product_no_platform_explicit');
|
|
192
|
+
}
|
|
193
|
+
return passthroughPlan(params, 'product_no_platform_signal', false);
|
|
194
|
+
}
|
|
195
|
+
// —— 无产品信号:纯透传
|
|
196
|
+
return passthroughPlan(params, 'no_product_signal', false);
|
|
197
|
+
}
|