kiku-agent 1.3.2 → 1.3.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.
- package/README.md +69 -12
- package/package.json +2 -1
- package/server/agent/agentCore.js +319 -46
- package/server/agent/appPaths.js +31 -0
- package/server/agent/audioPlayer.js +339 -12
- package/server/agent/autoContext.js +193 -0
- package/server/agent/catalogEntityResolver.js +170 -28
- package/server/agent/clarifyingQuestions.js +137 -35
- package/server/agent/cli.js +177 -48
- package/server/agent/cloudAdapters.js +116 -0
- package/server/agent/commandRegistry.js +409 -80
- package/server/agent/commands.js +1056 -125
- package/server/agent/config.js +1088 -690
- package/server/agent/contextCompactor.js +213 -21
- package/server/agent/cpuMetrics.js +199 -0
- package/server/agent/engineService.js +591 -0
- package/server/agent/eval/modules/evaluation/runner.js +4 -14
- package/server/agent/eval/modules/evaluation/scoring.js +15 -3
- package/server/agent/eval/modules/server/evalApi.js +5 -5
- package/server/agent/eval/modules/ui/evalUi.js +7 -4
- package/server/agent/eventBus.js +1 -0
- package/server/agent/ink/main.jsx +196 -191
- package/server/agent/jobManager.js +11 -1
- package/server/agent/lanDiscovery.js +721 -23
- package/server/agent/llmClient.js +317 -71
- package/server/agent/lmStudioWakeup.js +517 -65
- package/server/agent/locationService.js +797 -0
- package/server/agent/mcpQuizData.js +509 -0
- package/server/agent/memory/contextAllocator.js +19 -7
- package/server/agent/memory.js +3 -1
- package/server/agent/modelCompatibility.js +352 -0
- package/server/agent/modelDefaults.js +1 -0
- package/server/agent/modelManager.js +46 -2
- package/server/agent/newsWatch.js +9 -3
- package/server/agent/processManager.js +229 -0
- package/server/agent/prompts.js +174 -8
- package/server/agent/routingInterceptor.js +9 -1
- package/server/agent/sanitizer.js +41 -6
- package/server/agent/searchQueryPlanner.js +202 -0
- package/server/agent/session.js +59 -4
- package/server/agent/tests/agentFollowUps.test.js +128 -2
- package/server/agent/tests/agentMusicControl.test.js +245 -0
- package/server/agent/tests/apiRouter.test.js +1 -1
- package/server/agent/tests/autoContext.test.js +176 -0
- package/server/agent/tests/bilibiliEmbed.test.js +45 -0
- package/server/agent/tests/chatHardening.test.js +121 -0
- package/server/agent/tests/chineseWebSearchEscalation.test.js +62 -0
- package/server/agent/tests/clarifyingQuestions.test.js +33 -0
- package/server/agent/tests/cliAutomation.test.js +38 -1
- package/server/agent/tests/cloudProviders.test.js +91 -3
- package/server/agent/tests/commands.test.js +92 -3
- package/server/agent/tests/contextIntelligence.test.js +50 -3
- package/server/agent/tests/cpuMetrics.test.js +101 -0
- package/server/agent/tests/decisionAndSearchEnhancements.test.js +32 -0
- package/server/agent/tests/edgeCasesScenarios.test.js +82 -0
- package/server/agent/tests/engineService.test.js +436 -0
- package/server/agent/tests/engineUnload.test.js +94 -0
- package/server/agent/tests/envCommand.test.js +69 -0
- package/server/agent/tests/evalMetrics.test.js +8 -0
- package/server/agent/tests/fetchApi.test.js +99 -0
- package/server/agent/tests/hybridWebSearch.test.js +2 -0
- package/server/agent/tests/lanDiscovery.test.js +5 -0
- package/server/agent/tests/lanInterfaces.test.js +510 -0
- package/server/agent/tests/lmStudioWakeup.test.js +278 -0
- package/server/agent/tests/locationTool.test.js +278 -0
- package/server/agent/tests/memoryRoute.test.js +173 -0
- package/server/agent/tests/memoryUiNormalization.test.js +75 -0
- package/server/agent/tests/modelCompatibility.test.js +148 -0
- package/server/agent/tests/modelManager.test.js +32 -0
- package/server/agent/tests/musicControlUiBridge.test.js +113 -0
- package/server/agent/tests/nextGenArchitecture.test.js +4 -2
- package/server/agent/tests/openDomainPrompt.test.js +197 -0
- package/server/agent/tests/openDomainSearch.test.js +121 -0
- package/server/agent/tests/processManager.test.js +144 -0
- package/server/agent/tests/providerPersistence.test.js +10 -5
- package/server/agent/tests/quickActionsAndModals.test.js +180 -0
- package/server/agent/tests/searchQueryPlanner.test.js +108 -0
- package/server/agent/tests/securityAuditRemediation.test.js +16 -9
- package/server/agent/tests/securityAuditRemediations2.test.js +154 -0
- package/server/agent/tests/securityHardening.test.js +4 -4
- package/server/agent/tests/sessionAndCopy.test.js +39 -4
- package/server/agent/tests/sidebarControls.test.js +34 -0
- package/server/agent/tests/statefulMemory.test.js +8 -1
- package/server/agent/tests/textProtocolLoop.test.js +71 -0
- package/server/agent/tests/textToolParsing.test.js +48 -0
- package/server/agent/tests/toolRoutingRegressions.test.js +41 -0
- package/server/agent/tests/unifiedEndpoints.test.js +13 -6
- package/server/agent/tests/v110Features.test.js +1 -1
- package/server/agent/tests/vramEstimator.test.js +75 -0
- package/server/agent/tests/webChatDocs.test.js +199 -0
- package/server/agent/tests/webChatInferenceControl.test.js +298 -0
- package/server/agent/tests/webChatInspection.test.js +256 -5
- package/server/agent/tests/webChatMcp.test.js +94 -0
- package/server/agent/tests/webExtract.test.js +23 -0
- package/server/agent/tests/webSources.test.js +46 -12
- package/server/agent/textToolProtocol.js +173 -46
- package/server/agent/toolRouter.js +318 -44
- package/server/agent/tools.js +877 -96
- package/server/agent/ui.js +39 -34
- package/server/agent/vramService.js +35 -54
- package/server/agent/webSearch.js +441 -162
- package/server/agent/websearch/orchestrator.js +15 -5
- package/server/agent/websearch/resilience/cache.js +9 -2
- package/server/agent/websearch/security/ssrf.js +41 -10
- package/server/agent/youtubeAuth.js +5 -20
- package/server/apiRouter.js +5558 -4422
- package/server/mcp/data/discography.js +2 -2
- package/server/mcp/examples/antigravity.example.json +17 -0
- package/server/mcp/handler.js +8 -4
- package/server/mcp/security.js +220 -21
- package/server/mcp/server.js +2 -1
- package/server/mcp/tests/connection.test.js +14 -8
- package/server/mcp/tests/mcpKeyAuth.test.js +156 -0
- package/server/mcp/tools.js +7 -1
- package/server/supabase_migration_prefix.sql +102 -0
- package/server/supabase_schema.sql +18 -18
- package/server/web-chat/core/connection.js +179 -218
- package/server/web-chat/core/conversationContext.js +9 -2
- package/server/web-chat/core/directCatalogEngine.js +52 -28
- package/server/web-chat/core/dramaKnowledge.js +33 -22
- package/server/web-chat/core/followUpEngine.js +735 -81
- package/server/web-chat/core/futureEventGuard.js +5 -1
- package/server/web-chat/core/musicControlAction.js +70 -0
- package/server/web-chat/core/security.js +32 -21
- package/server/web-chat/core/toolInspector.js +6 -6
- package/server/web-chat/core/urlGuard.js +45 -0
- package/server/web-chat/router.js +204 -157
- package/server/web-chat/routes/chatRoute.js +885 -488
- package/server/web-chat/routes/engineRoute.js +270 -0
- package/server/web-chat/routes/exportRoute.js +1 -1
- package/server/web-chat/routes/lanDiscoveryRoute.js +17 -2
- package/server/web-chat/routes/lmStudioLoadRoute.js +172 -0
- package/server/web-chat/routes/mcpRoute.js +386 -0
- package/server/web-chat/routes/memoryRoute.js +253 -0
- package/server/web-chat/routes/providerRoute.js +49 -16
- package/server/web-chat/routes/staticRoute.js +306 -17
- package/server/web-chat/routes/statusRoute.js +194 -73
- package/server/web-chat/routes/suggestRoute.js +11 -3
- package/server/web-chat/routes/verifyRoute.js +26 -4
- package/server/web-chat/server.js +7 -6
- package/server/web-chat/ui/docsBuilder.js +3558 -0
- package/server/web-chat/ui/htmlBuilder.js +12 -0
- package/server/web-chat/ui/scripts/client.js +3401 -1302
- package/server/web-chat/ui/scripts/webchatI18n.js +155 -153
- package/server/web-chat/ui/settingsBuilder.js +7870 -0
- package/server/web-chat/ui/styles/lan-card.css +165 -0
- package/server/web-chat/ui/styles/main.css +4289 -447
- package/server/web-chat/ui/sw.js +64 -0
- package/server/web-chat/ui/templates/body.html +407 -281
- package/src/data/awardsData.js +146 -146
- package/src/data/musicVideoData.js +6 -4
- package/src/lib/vram/estimator.js +195 -19
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toolsSchema } from './tools.js';
|
|
2
|
-
import { resolveQueryEntities, detectPlatforms, detectPromotionIntent } from './catalogEntityResolver.js';
|
|
2
|
+
import { resolveQueryEntities, detectPlatforms, detectPromotionIntent, classifyQueryDomain, isQueryInDomain, classifyQuerySpectrum } from './catalogEntityResolver.js';
|
|
3
3
|
|
|
4
4
|
export const TOOL_CLUSTERS = Object.freeze({
|
|
5
5
|
CATALOG: [
|
|
@@ -22,6 +22,13 @@ export const TOOL_CLUSTERS = Object.freeze({
|
|
|
22
22
|
'stop_music',
|
|
23
23
|
'pause_music',
|
|
24
24
|
'resume_music',
|
|
25
|
+
'mute_music',
|
|
26
|
+
'unmute_music',
|
|
27
|
+
'set_volume',
|
|
28
|
+
'seek_music',
|
|
29
|
+
'set_repeat_mode',
|
|
30
|
+
'set_shuffle_mode',
|
|
31
|
+
'toggle_video_mode',
|
|
25
32
|
'next_track',
|
|
26
33
|
'prev_track',
|
|
27
34
|
'add_to_queue',
|
|
@@ -51,6 +58,9 @@ export const TOOL_CLUSTERS = Object.freeze({
|
|
|
51
58
|
'search_chinese_web',
|
|
52
59
|
'search_bilibili',
|
|
53
60
|
'search_web_images',
|
|
61
|
+
'get_user_location',
|
|
62
|
+
'search_location_map',
|
|
63
|
+
'get_weather',
|
|
54
64
|
],
|
|
55
65
|
SYSTEM: [
|
|
56
66
|
'get_system_stats',
|
|
@@ -63,6 +73,56 @@ export const TOOL_CLUSTERS = Object.freeze({
|
|
|
63
73
|
]
|
|
64
74
|
});
|
|
65
75
|
|
|
76
|
+
const TOOL_CLUSTER_MAP = new Map();
|
|
77
|
+
for (const [cluster, tools] of Object.entries(TOOL_CLUSTERS)) {
|
|
78
|
+
for (const t of tools) {
|
|
79
|
+
TOOL_CLUSTER_MAP.set(t, cluster);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getToolCluster(toolName) {
|
|
84
|
+
if (TOOL_CLUSTER_MAP.has(toolName)) return TOOL_CLUSTER_MAP.get(toolName);
|
|
85
|
+
if (toolName && toolName.startsWith('mcp_')) return 'SYSTEM';
|
|
86
|
+
return 'CATALOG';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const DEFAULT_OPEN_DOMAIN_TOOLS = Object.freeze([
|
|
90
|
+
'get_user_location',
|
|
91
|
+
'search_location_map',
|
|
92
|
+
'get_weather',
|
|
93
|
+
'web_search',
|
|
94
|
+
'web_extract',
|
|
95
|
+
'fetch_webpage',
|
|
96
|
+
'search_encyclopedia',
|
|
97
|
+
'search_news',
|
|
98
|
+
'fetch_json',
|
|
99
|
+
'global_search',
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
export const OPEN_DOMAIN_WEB_TOOLS = Object.freeze([
|
|
103
|
+
'web_search',
|
|
104
|
+
'web_extract',
|
|
105
|
+
'fetch_webpage',
|
|
106
|
+
'search_encyclopedia',
|
|
107
|
+
'search_news',
|
|
108
|
+
'fetch_json',
|
|
109
|
+
'fetch_api',
|
|
110
|
+
'fetch_rss',
|
|
111
|
+
'search_chinese_web',
|
|
112
|
+
'search_bilibili',
|
|
113
|
+
'search_youtube',
|
|
114
|
+
'search_web_images',
|
|
115
|
+
'search_music_platforms',
|
|
116
|
+
'get_youtube_transcript',
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
const CATALOG_INTENT_TYPES = new Set([
|
|
120
|
+
'WORKS',
|
|
121
|
+
'PROFILE_AWARDS_BRANDS',
|
|
122
|
+
'TIMELINE_ERA',
|
|
123
|
+
'MEDIA',
|
|
124
|
+
]);
|
|
125
|
+
|
|
66
126
|
const DEFAULT_UNIVERSAL_TOOLS = Object.freeze([
|
|
67
127
|
'global_search',
|
|
68
128
|
'get_profile_and_fandom',
|
|
@@ -105,13 +165,13 @@ export function expandActiveToolsWithDependencies(selectedTools, allToolsSchema)
|
|
|
105
165
|
const INTENT_PATTERNS = [
|
|
106
166
|
{
|
|
107
167
|
type: 'MEDIA',
|
|
108
|
-
regex: /(
|
|
168
|
+
regex: /(เพลง|ร้อง|ฟัง(?!ก์|กชัน)|เอ็มวี|\bmv\b|\bmusics?\b|\bsongs?\b|\bsingles?\b|\bsolos?\b|\balbums?\b|\bep\b|\bdiscography\b|\bdiscs?\b|\btracks?\b|\btunes?\b|\bmelod(?:y|ies)\b|\bplay\b|\bqueues?\b|\baudios?\b|\bsounds?\b|\blisten\b|\bstages?\b|\bdances?\b|\bdancing\b|\bconcerts?\b|\bost\b|\bbilibili\b|b站|\bqqmusic\b|\bspotify\b|(?<!เครื่อง)ดนตรี|อัลบั้ม|ซิงเกิล|โซโล่|歌曲|单曲|首发|舞台|演唱|คลิป|วิดีโอ|\bvideos?\b|หยุดเพลง|พักเพลง|เล่นต่อ|ข้ามเพลง|เพลงถัดไป|เพลงก่อนหน้า|(?<!เ)ปิดเพลง|ปรับเสียง|เพิ่มเสียง|ลดเสียง|(?<!เ)ปิดเสียง|เปิดเสียง|\bmute\b|\bunmute\b|\bvolume\b|\bpause\b|\bresume\b|\bnext\b|\bprev\b|\bseek\b|\bshuffle\b|\brepeat\b|\bloop\b|วนซ้ำ|สุ่มเพลง|กรอเพลง|วินาทีที่|นาทีที่|เปิด\s*mv|ดู\s*mv)/i,
|
|
109
169
|
clusters: ['MEDIA'],
|
|
110
|
-
essentialTools: ['search_discography', 'get_music_videos', '
|
|
170
|
+
essentialTools: ['search_discography', 'get_music_videos', 'search_bilibili', 'search_music_platforms', 'search_youtube', 'get_media_links', 'play_music', 'get_current_track', 'get_music_status', 'get_queue', 'get_gallery_photos']
|
|
111
171
|
},
|
|
112
172
|
{
|
|
113
173
|
type: 'WORKS',
|
|
114
|
-
regex: /(ละคร|ซีรีส์|หนัง|ภาพยนตร์|บทบาท|ตัวละคร|ตอน|ช่อง|ฉาย|\bdramas?\b|\bseries\b|\bmovies?\b|\bfilms?\b|\broles?\b|\bcharacters?\b|\bsynops(?:is|es)\b|\bactors?\b|\btv\b|\bworks?\b|\bbroadcast(?:s|ing)?\b
|
|
174
|
+
regex: /(ละคร|ซีรีส์|หนัง|ภาพยนตร์|บทบาท|ตัวละคร|ตอน|ช่อง|ฉาย|\bdramas?\b|\bseries\b|\bmovies?\b|\bfilms?\b|\broles?\b|\bcharacters?\b|\bsynops(?:is|es)\b|\bactors?\b|\btv\b|\bworks?\b|\bbroadcast(?:s|ing)?\b|影视|剧|新剧|角色|饰演)/i,
|
|
115
175
|
clusters: ['CATALOG'],
|
|
116
176
|
essentialTools: ['search_works', 'get_work_detail', 'get_character_roles', 'global_search', 'get_career_timeline', 'get_gallery_photos']
|
|
117
177
|
},
|
|
@@ -129,20 +189,59 @@ const INTENT_PATTERNS = [
|
|
|
129
189
|
},
|
|
130
190
|
{
|
|
131
191
|
type: 'RESEARCH_VERIFY',
|
|
132
|
-
regex: /(
|
|
192
|
+
regex: /(ข่าว|ล่าสุด|ใหม่ล่าสุด|ตอนนี้|ช่วงนี้|ปัจจุบัน|ปีนี้|ตารางงาน|ความเคลื่อนไหว|จริงไหม|ข่าวลือ|สืบ|ตรวจสอบ|สัญญา|ศาล|\bstar48\b|\bsiba\b|\bnews\b|\bupdates?\b|\blatest\b|\brecent(?:ly)?\b|\brumors?\b|\bverify\b|\bclaims?\b|\bdisputes?\b|\blegal\b|\blawsuits?\b|\bcontracts?\b|\btruth\b|\bweibo\b|เว่ยป๋อ|微博|超话|\bxiaohongshu\b|เสี่ยวหงซู|小红书|\bdouyin\b|โต่วอิน|抖音|路透|开机|新剧|行程|\bcurrently\b|\bnowadays\b|\bthese days\b|新闻|最新消息|动态|热搜|资讯|爆料|近况|百科|百度百科|维基|\bencyclopedia\b|\bbaike\b|\bwikipedia?\b)/i,
|
|
133
193
|
clusters: ['RESEARCH'],
|
|
134
|
-
essentialTools: ['verify_claim', 'web_search', 'web_extract', 'fetch_webpage', 'run_subagent', 'run_deep_research', 'global_search', 'search_news', 'search_encyclopedia', 'search_chinese_web'
|
|
194
|
+
essentialTools: ['verify_claim', 'web_search', 'web_extract', 'fetch_webpage', 'run_subagent', 'run_deep_research', 'global_search', 'search_news', 'search_encyclopedia', 'search_chinese_web']
|
|
135
195
|
},
|
|
136
196
|
{
|
|
137
197
|
type: 'SYSTEM_SKILL',
|
|
138
|
-
regex: /(
|
|
198
|
+
regex: /(?:\bskills?\b|\bmanage_skill\b|\btui\b|\bsystems?\b|\bstats\b|\bstatus\b|\bmemory\b|\bprefs?\b|\bfiles?\b|\bdirs?\b|\bdirector(?:y|ies)\b|สถิติระบบ|สถานะระบบ|ระบบไฟล์|สอน\s*(?:kiku|บอต|ai|ระบบ|เธอ|คุณ|น้องจวี)|เรียนรู้ทักษะ|จัดการสกิล|\bteach\s*(?:kiku|the\s*bot|the\s*ai|the\s*system|you)\b|\blearn\s*(?:skill|preference|instruction)\b)/i,
|
|
139
199
|
clusters: ['SYSTEM'],
|
|
140
200
|
essentialTools: ['manage_skill', 'get_system_stats', 'read_local_file', 'list_directory']
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
type: 'LOCATION_WEATHER',
|
|
204
|
+
regex: /(สภาพอากาศ|พยากรณ์อากาศ|อากาศ|ฝนตก|อุณหภูมิ|กี่องศา|ร่ม|แดด|หนาว|ร้อน|พายุ|แถวนี้|ใกล้ฉัน|ที่นี่|พิกัด|ตำแหน่ง|\bweather\b|\btemperature\b|\bforecast\b|\brain\b|\bclimate\b|\bnearby\b|\baround here\b|\bhere\b|\blocation\b|\bcoords?\b|\bgeolocation\b)/i,
|
|
205
|
+
clusters: ['RESEARCH'],
|
|
206
|
+
essentialTools: ['get_weather', 'get_user_location', 'search_location_map', 'web_search', 'fetch_json', 'fetch_webpage']
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
type: 'MAP_NAVIGATION',
|
|
210
|
+
regex: /(แผนที่|ขอแผนที่|ปักหมุด|นำทาง|ทางไป|อยู่ตรงไหน|อยู่ที่ไหน|พิกัดของ|เปิดแมพ|แมพ|\bmap of\b|\bmap\b|\bosm\b|\bopenstreetmap\b|\bdirections?\b|\bnavigation\b|\bwhere is\b)/i,
|
|
211
|
+
clusters: ['RESEARCH'],
|
|
212
|
+
essentialTools: ['search_location_map', 'get_user_location', 'web_search']
|
|
141
213
|
}
|
|
142
214
|
];
|
|
143
215
|
|
|
144
216
|
const MAX_ROUTED_TOOLS = 15;
|
|
145
217
|
|
|
218
|
+
export function calculateSearchEscalationScore(prompt = '') {
|
|
219
|
+
const text = String(prompt || '');
|
|
220
|
+
let score = 0;
|
|
221
|
+
|
|
222
|
+
// Factor 1: Recency and temporal live markers
|
|
223
|
+
if (/(?:ล่าสุด|ใหม่ล่าสุด|ตอนนี้|ช่วงนี้|ปัจจุบัน|ปีนี้|ปี\s*(?:202[4-9]|256[7-9])|\b202[4-9]\b|latest|newest|recent(?:ly)?|current(?:ly)?|today|nowadays|these days|最新|近期|现在|近况)/i.test(text)) {
|
|
224
|
+
score += 15;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Factor 2: Social media, live events, ongoing production
|
|
228
|
+
if (/(?:\bweibo\b|เว่ยป๋อ|微博|超话|\bxiaohongshu\b|เสี่ยวหงซู|小红书|\bdouyin\b|โต่วอิน|抖音|路透|开机|新剧|行程|ตารางงาน|งานอีเวนต์|อีเวนต์|แฟนมีต|แฟนมีตติ้ง|คอนเสิร์ต|ไลฟ์สด|\blive\b|直播)/i.test(text)) {
|
|
229
|
+
score += 15;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Factor 3: News, verification, rumors, controversies
|
|
233
|
+
if (/(?:ข่าว|ข่าวลือ|จริงไหม|สืบ|อัปเดต|ความเคลื่อนไหว|สัญญากับ|\bstar48\b|\bsiba\b|\bnews\b|\brumor(?:s)?\b|\bupdates?\b|\bdispute|\blawsuit|\bcontroversy|新闻|资讯|动态|热搜|爆料)/i.test(text)) {
|
|
234
|
+
score += 20;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Factor 4: Inquiring about external presence / web / internet
|
|
238
|
+
if (/(?:ค้นหาเว็บ|ค้นหาในเน็ต|เสิร์ช|กูเกิล|baidu|ไป่ตู้|เน็ต|อินเทอร์เน็ต|\bweb\b|\bsearch\b|\bgoogle\b|\bbaidu\b|上网查|网上|搜索)/i.test(text)) {
|
|
239
|
+
score += 15;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return Math.min(score, 60);
|
|
243
|
+
}
|
|
244
|
+
|
|
146
245
|
export class DynamicToolRouter {
|
|
147
246
|
constructor(allTools = toolsSchema) {
|
|
148
247
|
this.allTools = Array.isArray(allTools) ? allTools : toolsSchema;
|
|
@@ -158,48 +257,56 @@ export class DynamicToolRouter {
|
|
|
158
257
|
const text = String(prompt || '');
|
|
159
258
|
const matched = [];
|
|
160
259
|
const matchedTypes = new Set();
|
|
260
|
+
const resolution = resolveQueryEntities(text);
|
|
261
|
+
const intentScores = new Map();
|
|
161
262
|
|
|
263
|
+
const addScore = (type, score) => {
|
|
264
|
+
intentScores.set(type, (intentScores.get(type) || 0) + score);
|
|
265
|
+
};
|
|
162
266
|
|
|
163
267
|
for (const pattern of INTENT_PATTERNS) {
|
|
164
268
|
if (pattern.regex.test(text)) {
|
|
165
|
-
|
|
166
|
-
matchedTypes.add(pattern.type);
|
|
269
|
+
addScore(pattern.type, 3);
|
|
167
270
|
}
|
|
168
271
|
}
|
|
169
272
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if ((resolution.hasBrand || resolution.isPromotion) && !matchedTypes.has('PROFILE_AWARDS_BRANDS')) {
|
|
174
|
-
const brandPattern = INTENT_PATTERNS.find(p => p.type === 'PROFILE_AWARDS_BRANDS');
|
|
175
|
-
if (brandPattern) {
|
|
176
|
-
matched.push(brandPattern);
|
|
177
|
-
matchedTypes.add('PROFILE_AWARDS_BRANDS');
|
|
178
|
-
}
|
|
273
|
+
if (/(?:หยุดเพลง|พักเพลง|เล่นต่อ|ข้ามเพลง|เพลงถัดไป|เพลงก่อนหน้า|(?<!เ)ปิดเพลง|ปรับเสียง|เพิ่มเสียง|ลดเสียง|(?<!เ)ปิดเสียง|เปิดเสียง|\bmute\b|\bunmute\b|\bvolume\b|\bpause\b|\bresume\b|\bnext\b|\bprev\b|\bseek\b|\bshuffle\b|\brepeat\b|\bloop\b|วนซ้ำ|สุ่มเพลง|กรอเพลง|วินาทีที่|นาทีที่|เปิด\s*mv|ดู\s*mv|toggle_video)/i.test(text)) {
|
|
274
|
+
addScore('MEDIA', 5);
|
|
179
275
|
}
|
|
276
|
+
if (resolution.hasSong) addScore('MEDIA', 4);
|
|
277
|
+
const mediaPlatforms = resolution.platforms.filter(p => ['bilibili', 'youtube', 'qqmusic', 'douyin'].includes(p));
|
|
278
|
+
if (mediaPlatforms.length > 0) addScore('MEDIA', 3);
|
|
180
279
|
|
|
181
|
-
if (resolution.hasWork
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
matchedTypes.add('WORKS');
|
|
186
|
-
}
|
|
187
|
-
}
|
|
280
|
+
if (resolution.hasWork) addScore('WORKS', 4);
|
|
281
|
+
|
|
282
|
+
if (resolution.hasBrand || resolution.isPromotion) addScore('PROFILE_AWARDS_BRANDS', 4);
|
|
283
|
+
if (resolution.hasAward || resolution.isAwardIntent) addScore('PROFILE_AWARDS_BRANDS', 5);
|
|
188
284
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
285
|
+
const sortedIntents = [...intentScores.entries()]
|
|
286
|
+
.filter(([, score]) => score >= 3)
|
|
287
|
+
.sort((a, b) => b[1] - a[1]);
|
|
288
|
+
|
|
289
|
+
for (const [type, score] of sortedIntents) {
|
|
290
|
+
const p = INTENT_PATTERNS.find(item => item.type === type);
|
|
291
|
+
if (p) {
|
|
292
|
+
matched.push({ ...p, score });
|
|
293
|
+
matchedTypes.add(type);
|
|
194
294
|
}
|
|
195
295
|
}
|
|
196
296
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
297
|
+
const spectrum = classifyQuerySpectrum(text);
|
|
298
|
+
const hasCatalogSignal = resolution.matchedEntities.length > 0;
|
|
299
|
+
const offTopicEnforced = spectrum.verdict === 'OPEN_DOMAIN' && !hasCatalogSignal;
|
|
300
|
+
if (spectrum.verdict === 'OPEN_DOMAIN' || spectrum.bias < 0.4) {
|
|
301
|
+
matched.push({
|
|
302
|
+
type: 'OPEN_DOMAIN',
|
|
303
|
+
regex: /.*/,
|
|
304
|
+
clusters: ['RESEARCH'],
|
|
305
|
+
essentialTools: offTopicEnforced ? [...OPEN_DOMAIN_WEB_TOOLS] : ['web_search', 'web_extract', 'fetch_webpage', 'search_encyclopedia', 'search_news'],
|
|
306
|
+
score: offTopicEnforced ? 6 : Math.max(1, Math.round((1 - spectrum.bias) * 5)),
|
|
307
|
+
...(offTopicEnforced ? { enforced: true } : {})
|
|
308
|
+
});
|
|
309
|
+
matchedTypes.add('OPEN_DOMAIN');
|
|
203
310
|
}
|
|
204
311
|
|
|
205
312
|
return matched;
|
|
@@ -245,8 +352,22 @@ export class DynamicToolRouter {
|
|
|
245
352
|
|
|
246
353
|
const matchedIntents = this.detectIntents(prompt);
|
|
247
354
|
const resolution = resolveQueryEntities(prompt);
|
|
355
|
+
const searchEscalationScore = calculateSearchEscalationScore(prompt);
|
|
356
|
+
const openIntent = matchedIntents.find(i => i.type === 'OPEN_DOMAIN');
|
|
357
|
+
const forceOpenDomain = Boolean(openIntent && openIntent.enforced)
|
|
358
|
+
&& resolution.matchedEntities.length === 0;
|
|
359
|
+
|
|
360
|
+
if (searchEscalationScore >= 15) {
|
|
361
|
+
selectedNames.add('search_chinese_web');
|
|
362
|
+
selectedNames.add('search_news');
|
|
363
|
+
selectedNames.add('web_search');
|
|
364
|
+
selectedNames.add('web_extract');
|
|
365
|
+
highPriorityTools.add('search_chinese_web');
|
|
366
|
+
highPriorityTools.add('search_news');
|
|
367
|
+
highPriorityTools.add('web_search');
|
|
368
|
+
}
|
|
369
|
+
|
|
248
370
|
|
|
249
|
-
|
|
250
371
|
for (const entity of resolution.matchedEntities) {
|
|
251
372
|
for (const toolName of (entity.recommendedTools || [])) {
|
|
252
373
|
selectedNames.add(toolName);
|
|
@@ -254,35 +375,135 @@ export class DynamicToolRouter {
|
|
|
254
375
|
}
|
|
255
376
|
}
|
|
256
377
|
|
|
257
|
-
|
|
378
|
+
for (const toolName of (resolution.recommendedTools || [])) {
|
|
379
|
+
selectedNames.add(toolName);
|
|
380
|
+
highPriorityTools.add(toolName);
|
|
381
|
+
}
|
|
382
|
+
|
|
258
383
|
if (resolution.hasBrand || resolution.isPromotion) {
|
|
259
384
|
selectedNames.add('get_brand_endorsements');
|
|
260
385
|
highPriorityTools.add('get_brand_endorsements');
|
|
261
386
|
}
|
|
262
387
|
|
|
388
|
+
if (resolution.hasAward || resolution.isAwardIntent) {
|
|
389
|
+
selectedNames.add('get_awards');
|
|
390
|
+
highPriorityTools.add('get_awards');
|
|
391
|
+
}
|
|
392
|
+
|
|
263
393
|
if (resolution.platforms.includes('bilibili')) {
|
|
264
394
|
selectedNames.add('search_bilibili');
|
|
265
|
-
selectedNames.add('get_media_links');
|
|
266
395
|
highPriorityTools.add('search_bilibili');
|
|
396
|
+
if (!forceOpenDomain) {
|
|
397
|
+
selectedNames.add('get_media_links');
|
|
398
|
+
highPriorityTools.add('get_media_links');
|
|
399
|
+
}
|
|
267
400
|
}
|
|
268
401
|
|
|
269
402
|
if (resolution.platforms.includes('youtube')) {
|
|
270
403
|
selectedNames.add('search_youtube');
|
|
271
|
-
selectedNames.add('get_media_links');
|
|
272
404
|
highPriorityTools.add('search_youtube');
|
|
405
|
+
if (!forceOpenDomain) {
|
|
406
|
+
selectedNames.add('get_media_links');
|
|
407
|
+
highPriorityTools.add('get_media_links');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (/(เปิดเพลง|เล่นเพลง|\bplay(?:_music)?\b)/i.test(prompt)) {
|
|
412
|
+
selectedNames.add('play_music');
|
|
413
|
+
highPriorityTools.add('play_music');
|
|
414
|
+
}
|
|
415
|
+
if (/(ปรับเสียง|เพิ่มเสียง|ลดเสียง|\bvolume\b)/i.test(prompt)) {
|
|
416
|
+
selectedNames.add('set_volume');
|
|
417
|
+
highPriorityTools.add('set_volume');
|
|
418
|
+
}
|
|
419
|
+
if (/(?:(?<!เ)ปิดเสียง|เปิดเสียง|\bmute\b|\bunmute\b)/i.test(prompt)) {
|
|
420
|
+
selectedNames.add('mute_music');
|
|
421
|
+
selectedNames.add('unmute_music');
|
|
422
|
+
highPriorityTools.add('mute_music');
|
|
423
|
+
highPriorityTools.add('unmute_music');
|
|
424
|
+
}
|
|
425
|
+
if (/(กรอเพลง|วินาทีที่|นาทีที่|\bseek\b)/i.test(prompt)) {
|
|
426
|
+
selectedNames.add('seek_music');
|
|
427
|
+
highPriorityTools.add('seek_music');
|
|
428
|
+
}
|
|
429
|
+
if (/(วนซ้ำ|\brepeat\b|\bloop\b)/i.test(prompt)) {
|
|
430
|
+
selectedNames.add('set_repeat_mode');
|
|
431
|
+
highPriorityTools.add('set_repeat_mode');
|
|
432
|
+
}
|
|
433
|
+
if (/(สุ่มเพลง|\bshuffle\b)/i.test(prompt)) {
|
|
434
|
+
selectedNames.add('set_shuffle_mode');
|
|
435
|
+
highPriorityTools.add('set_shuffle_mode');
|
|
436
|
+
}
|
|
437
|
+
if (/(เปิด\s*mv|ดู\s*mv|สลับ\s*mv|toggle_video)/i.test(prompt)) {
|
|
438
|
+
selectedNames.add('toggle_video_mode');
|
|
439
|
+
highPriorityTools.add('toggle_video_mode');
|
|
440
|
+
}
|
|
441
|
+
if (/(หยุดเพลง|พักเพลง|\bpause\b)/i.test(prompt)) {
|
|
442
|
+
selectedNames.add('pause_music');
|
|
443
|
+
highPriorityTools.add('pause_music');
|
|
444
|
+
}
|
|
445
|
+
if (/(เล่นต่อ|\bresume\b)/i.test(prompt)) {
|
|
446
|
+
selectedNames.add('resume_music');
|
|
447
|
+
highPriorityTools.add('resume_music');
|
|
448
|
+
}
|
|
449
|
+
if (/(ข้ามเพลง|เพลงถัดไป|\bnext\b)/i.test(prompt)) {
|
|
450
|
+
selectedNames.add('next_track');
|
|
451
|
+
highPriorityTools.add('next_track');
|
|
452
|
+
}
|
|
453
|
+
if (/(เพลงก่อนหน้า|\bprev\b)/i.test(prompt)) {
|
|
454
|
+
selectedNames.add('prev_track');
|
|
455
|
+
highPriorityTools.add('prev_track');
|
|
456
|
+
}
|
|
457
|
+
if (/(?:(?<!เ)ปิดเพลง|เลิกฟังเพลง|\bstop_music\b)/i.test(prompt)) {
|
|
458
|
+
selectedNames.add('stop_music');
|
|
459
|
+
highPriorityTools.add('stop_music');
|
|
460
|
+
}
|
|
461
|
+
if (/(สภาพอากาศ|พยากรณ์อากาศ|อากาศ|ฝนตก|อุณหภูมิ|กี่องศา|ร่ม|แดด|หนาว|ร้อน|พายุ|แถวนี้|ใกล้ฉัน|ที่นี่|พิกัด|ตำแหน่ง|\bweather\b|\btemperature\b|\bforecast\b|\brain\b|\bclimate\b|\bnearby\b|\baround here\b|\bhere\b|\blocation\b|\bcoords?\b|\bgeolocation\b)/i.test(prompt)) {
|
|
462
|
+
selectedNames.add('get_weather');
|
|
463
|
+
highPriorityTools.add('get_weather');
|
|
464
|
+
selectedNames.add('get_user_location');
|
|
465
|
+
highPriorityTools.add('get_user_location');
|
|
466
|
+
selectedNames.add('web_search');
|
|
467
|
+
highPriorityTools.add('web_search');
|
|
468
|
+
}
|
|
469
|
+
if (/(แผนที่|ขอแผนที่|ปักหมุด|นำทาง|ทางไป|อยู่ตรงไหน|อยู่ที่ไหน|พิกัดของ|เปิดแมพ|แมพ|\bmap of\b|\bmap\b|\bosm\b|\bopenstreetmap\b|\bdirections?\b|\bnavigation\b|\bwhere is\b)/i.test(prompt)) {
|
|
470
|
+
selectedNames.add('search_location_map');
|
|
471
|
+
highPriorityTools.add('search_location_map');
|
|
472
|
+
selectedNames.add('get_user_location');
|
|
273
473
|
}
|
|
274
474
|
|
|
275
475
|
if (matchedIntents.length === 0) {
|
|
276
|
-
|
|
476
|
+
const isDomain = isQueryInDomain(prompt) || /^(?:สวัสดี|hello|hi|hey|หวัดดี|ดีครับ|ดีค่ะ)/i.test(prompt);
|
|
477
|
+
const fallbackTools = isDomain ? DEFAULT_UNIVERSAL_TOOLS : DEFAULT_OPEN_DOMAIN_TOOLS;
|
|
478
|
+
for (const name of fallbackTools) {
|
|
277
479
|
selectedNames.add(name);
|
|
278
480
|
}
|
|
279
481
|
} else {
|
|
482
|
+
const isOpenDomain = matchedIntents.some(i => i.type === 'OPEN_DOMAIN');
|
|
280
483
|
for (const intent of matchedIntents) {
|
|
484
|
+
if (forceOpenDomain && CATALOG_INTENT_TYPES.has(intent.type)) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
if (isOpenDomain && !resolution.hasWork && !resolution.hasBrand && (intent.type === 'WORKS' || intent.type === 'PROFILE_AWARDS_BRANDS')) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
281
490
|
for (const toolName of intent.essentialTools) {
|
|
282
491
|
selectedNames.add(toolName);
|
|
283
492
|
}
|
|
284
493
|
}
|
|
285
|
-
|
|
494
|
+
if (isOpenDomain) {
|
|
495
|
+
highPriorityTools.add('web_search');
|
|
496
|
+
highPriorityTools.add('search_encyclopedia');
|
|
497
|
+
}
|
|
498
|
+
if (forceOpenDomain) {
|
|
499
|
+
for (const name of OPEN_DOMAIN_WEB_TOOLS) {
|
|
500
|
+
selectedNames.add(name);
|
|
501
|
+
highPriorityTools.add(name);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (!forceOpenDomain) {
|
|
505
|
+
selectedNames.add('global_search');
|
|
506
|
+
}
|
|
286
507
|
selectedNames.add('web_search');
|
|
287
508
|
selectedNames.add('web_extract');
|
|
288
509
|
}
|
|
@@ -313,13 +534,17 @@ export class DynamicToolRouter {
|
|
|
313
534
|
}
|
|
314
535
|
|
|
315
536
|
for (const intent of matchedIntents) {
|
|
537
|
+
if (forceOpenDomain && CATALOG_INTENT_TYPES.has(intent.type)) continue;
|
|
316
538
|
for (const toolName of intent.essentialTools) {
|
|
317
539
|
addToolByName(toolName);
|
|
318
540
|
}
|
|
319
541
|
}
|
|
320
542
|
|
|
321
543
|
if (matchedIntents.length > 0) {
|
|
322
|
-
|
|
544
|
+
const guaranteed = forceOpenDomain
|
|
545
|
+
? ['web_search', 'web_extract', 'search_encyclopedia', 'search_news']
|
|
546
|
+
: ['global_search', 'web_search', 'web_extract'];
|
|
547
|
+
for (const name of guaranteed) {
|
|
323
548
|
addToolByName(name);
|
|
324
549
|
}
|
|
325
550
|
}
|
|
@@ -352,7 +577,56 @@ export class DynamicToolRouter {
|
|
|
352
577
|
}
|
|
353
578
|
|
|
354
579
|
if (bundled.length > MAX_ROUTED_TOOLS && !options.showAll) {
|
|
355
|
-
|
|
580
|
+
const priority = (toolName) => {
|
|
581
|
+
if (pinnedTools.some(t => t.function?.name === toolName)) return 100;
|
|
582
|
+
let score = 0;
|
|
583
|
+
if (highPriorityTools.has(toolName)) score += 20;
|
|
584
|
+
if (selectedNames.has(toolName)) score += 10;
|
|
585
|
+
if (searchEscalationScore > 0 && ['search_chinese_web', 'search_news', 'web_search'].includes(toolName)) {
|
|
586
|
+
score += Math.min(Math.round(searchEscalationScore * 0.4), 12);
|
|
587
|
+
}
|
|
588
|
+
for (let i = 0; i < matchedIntents.length; i++) {
|
|
589
|
+
const intent = matchedIntents[i];
|
|
590
|
+
const rank = intent.essentialTools ? intent.essentialTools.indexOf(toolName) : -1;
|
|
591
|
+
if (rank !== -1) {
|
|
592
|
+
score += Math.max(1, 15 - i * 3 - rank);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return score;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const ranked = [...bundled].sort((a, b) => {
|
|
599
|
+
const nameA = a.function?.name || a.name;
|
|
600
|
+
const nameB = b.function?.name || b.name;
|
|
601
|
+
return priority(nameB) - priority(nameA);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
const kept = [];
|
|
605
|
+
const perCluster = new Map();
|
|
606
|
+
const overflow = [];
|
|
607
|
+
|
|
608
|
+
for (const tool of ranked) {
|
|
609
|
+
const name = tool.function?.name || tool.name;
|
|
610
|
+
if (pinnedTools.some(t => (t.function?.name || t.name) === name)) {
|
|
611
|
+
kept.push(tool);
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
const cluster = getToolCluster(name);
|
|
615
|
+
const count = perCluster.get(cluster) || 0;
|
|
616
|
+
if (count < 7) {
|
|
617
|
+
kept.push(tool);
|
|
618
|
+
perCluster.set(cluster, count + 1);
|
|
619
|
+
if (kept.length >= MAX_ROUTED_TOOLS) break;
|
|
620
|
+
} else {
|
|
621
|
+
overflow.push(tool);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
while (kept.length < MAX_ROUTED_TOOLS && overflow.length > 0) {
|
|
626
|
+
kept.push(overflow.shift());
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return kept;
|
|
356
630
|
}
|
|
357
631
|
|
|
358
632
|
return bundled;
|