kiku-agent 1.3.1 → 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 +5 -12
- 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/AGENTS.md +228 -0
- package/server/agent/eval/analyze.py +684 -0
- package/server/agent/eval/gates.json +15 -0
- package/server/agent/eval/modules/analysis/compare.js +198 -0
- package/server/agent/eval/modules/analysis/gates.js +72 -0
- package/server/agent/eval/modules/analysis/judge.js +70 -0
- package/server/agent/eval/modules/core/cli.js +453 -0
- package/server/agent/eval/modules/core/config.js +60 -0
- package/server/agent/eval/modules/core/store.js +236 -0
- package/server/agent/eval/modules/evaluation/cases.js +689 -0
- package/server/agent/eval/modules/evaluation/runner.js +288 -0
- package/server/agent/eval/modules/evaluation/scoring.js +363 -0
- package/server/agent/eval/modules/evaluation/worker.js +122 -0
- package/server/agent/eval/modules/reporting/benchmark.js +265 -0
- package/server/agent/eval/modules/reporting/benchmarkPng.js +487 -0
- package/server/agent/eval/modules/reporting/dashboard.js +1406 -0
- package/server/agent/eval/modules/server/evalApi.js +1099 -0
- package/server/agent/eval/modules/ui/evalUi.js +4799 -0
- package/server/agent/eval/modules/utils/smokes.js +119 -0
- 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/agentBubbleSystem.test.js +65 -0
- package/server/agent/tests/agentFollowUps.test.js +253 -0
- package/server/agent/tests/agentMusicControl.test.js +245 -0
- package/server/agent/tests/apiRouter.test.js +108 -0
- package/server/agent/tests/architectureFixes.test.js +81 -0
- package/server/agent/tests/architectureRefactoring.test.js +194 -0
- package/server/agent/tests/autoContext.test.js +176 -0
- package/server/agent/tests/autoResearch.test.js +64 -0
- package/server/agent/tests/bilibiliEmbed.test.js +296 -0
- package/server/agent/tests/catalogSync.test.js +130 -0
- package/server/agent/tests/chatHardening.test.js +121 -0
- package/server/agent/tests/chineseWebSearchEscalation.test.js +62 -0
- package/server/agent/tests/citations.test.js +180 -0
- package/server/agent/tests/clarificationAnalytics.test.js +219 -0
- package/server/agent/tests/clarifyingQuestions.test.js +627 -0
- package/server/agent/tests/cliAutomation.test.js +158 -0
- package/server/agent/tests/cloudProviders.test.js +322 -0
- package/server/agent/tests/commandInput.test.js +24 -0
- package/server/agent/tests/commands.test.js +506 -0
- package/server/agent/tests/contextIntelligence.test.js +209 -0
- package/server/agent/tests/conversationSafety.test.js +53 -0
- package/server/agent/tests/cpuMetrics.test.js +101 -0
- package/server/agent/tests/decisionAndSearchEnhancements.test.js +167 -0
- package/server/agent/tests/dramaAnswerQuality.test.js +73 -0
- package/server/agent/tests/dynamicCatalogIngestion.test.js +285 -0
- package/server/agent/tests/dynamicRoutingAndSearch.test.js +92 -0
- package/server/agent/tests/edgeCasesScenarios.test.js +131 -0
- package/server/agent/tests/engineService.test.js +436 -0
- package/server/agent/tests/engineUnload.test.js +94 -0
- package/server/agent/tests/entertainmentMetrics.test.js +126 -0
- package/server/agent/tests/envBootstrap.test.js +87 -0
- package/server/agent/tests/envCommand.test.js +284 -0
- package/server/agent/tests/errorHandling.test.js +80 -0
- package/server/agent/tests/errors.test.js +13 -0
- package/server/agent/tests/evalAnalyze.test.js +54 -0
- package/server/agent/tests/evalCommand.test.js +54 -0
- package/server/agent/tests/evalCorpus.test.js +126 -0
- package/server/agent/tests/evalHarness.test.js +62 -0
- package/server/agent/tests/evalJudgeContext.test.js +38 -0
- package/server/agent/tests/evalMetrics.test.js +320 -0
- package/server/agent/tests/evalStore.test.js +190 -0
- package/server/agent/tests/evalStudio.test.js +179 -0
- package/server/agent/tests/feedbackLearning.test.js +186 -0
- package/server/agent/tests/fetchApi.test.js +99 -0
- package/server/agent/tests/firstRun.test.js +44 -0
- package/server/agent/tests/gemma4eOptimization.test.js +95 -0
- package/server/agent/tests/hardwareTiers.test.js +206 -0
- package/server/agent/tests/hybridWebSearch.test.js +194 -0
- package/server/agent/tests/judgeService.test.js +251 -0
- package/server/agent/tests/lanDiscovery.test.js +324 -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/mcpClient.test.js +201 -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 +141 -0
- package/server/agent/tests/multilingualScenarios.test.js +69 -0
- package/server/agent/tests/musicControlUiBridge.test.js +113 -0
- package/server/agent/tests/newCommands.test.js +347 -0
- package/server/agent/tests/newCommandsTui.test.js +141 -0
- package/server/agent/tests/newTools.test.js +113 -0
- package/server/agent/tests/newsIntelligence.test.js +178 -0
- package/server/agent/tests/nextGenArchitecture.test.js +101 -0
- package/server/agent/tests/offlineInput.test.js +217 -0
- package/server/agent/tests/openDomainPrompt.test.js +197 -0
- package/server/agent/tests/openDomainSearch.test.js +121 -0
- package/server/agent/tests/packagingGuard.test.js +57 -0
- package/server/agent/tests/presentation.test.js +61 -0
- package/server/agent/tests/processManager.test.js +144 -0
- package/server/agent/tests/providerPersistence.test.js +44 -0
- package/server/agent/tests/queryBenchmarks.test.js +83 -0
- package/server/agent/tests/queryDetails.test.js +126 -0
- package/server/agent/tests/quickActionsAndModals.test.js +180 -0
- package/server/agent/tests/realWorldValidation.test.js +391 -0
- package/server/agent/tests/resilienceAndConcurrency.test.js +117 -0
- package/server/agent/tests/runtimeWatchdog.test.js +32 -0
- package/server/agent/tests/sanitizer.test.js +37 -0
- package/server/agent/tests/scenariosData.js +378 -0
- package/server/agent/tests/schemaRouting.test.js +54 -0
- package/server/agent/tests/searchQueryPlanner.test.js +108 -0
- package/server/agent/tests/securityAuditRemediation.test.js +221 -0
- package/server/agent/tests/securityAuditRemediations2.test.js +154 -0
- package/server/agent/tests/securityHardening.test.js +146 -0
- package/server/agent/tests/securitySanitizer.test.js +38 -0
- package/server/agent/tests/sessionAndCopy.test.js +267 -0
- package/server/agent/tests/sidebarControls.test.js +135 -0
- package/server/agent/tests/statefulMemory.test.js +277 -0
- package/server/agent/tests/subagent.test.js +216 -0
- package/server/agent/tests/subagentProgress.test.js +109 -0
- package/server/agent/tests/subagentTextFallback.test.js +115 -0
- package/server/agent/tests/suggestions.test.js +199 -0
- package/server/agent/tests/suggestionsTui.test.js +251 -0
- package/server/agent/tests/telemetryAndProfiles.test.js +179 -0
- package/server/agent/tests/terminalImage.test.js +80 -0
- package/server/agent/tests/terminalMarkdown.test.js +166 -0
- package/server/agent/tests/terminalText.test.js +133 -0
- package/server/agent/tests/textProtocolLoop.test.js +197 -0
- package/server/agent/tests/textToolParsing.test.js +187 -0
- package/server/agent/tests/theme.test.js +26 -0
- package/server/agent/tests/toolRegistryParity.test.js +53 -0
- package/server/agent/tests/toolRoutingRegressions.test.js +160 -0
- package/server/agent/tests/tools.test.js +259 -0
- package/server/agent/tests/unifiedEndpoints.test.js +159 -0
- package/server/agent/tests/v110Features.test.js +262 -0
- package/server/agent/tests/versionBump.test.js +69 -0
- package/server/agent/tests/vramEstimator.test.js +595 -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 +551 -0
- package/server/agent/tests/webChatMcp.test.js +94 -0
- package/server/agent/tests/webChatMemory.test.js +112 -0
- package/server/agent/tests/webChatSecurity.test.js +169 -0
- package/server/agent/tests/webExtract.test.js +284 -0
- package/server/agent/tests/webSources.test.js +281 -0
- 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/eval/judgeRubrics.js +110 -0
- package/server/eval/judgeService.js +290 -0
- package/server/eval/runBenchmark.js +182 -0
- package/server/mcp/data/discography.js +2 -2
- package/server/mcp/examples/antigravity.example.json +17 -0
- package/server/mcp/examples/librechat.example.yaml +16 -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 +162 -0
- 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 +63 -0
- 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
|
@@ -14,13 +14,13 @@ import { AgentSession } from './session.js';
|
|
|
14
14
|
import { ResearchSubagent } from './subagent.js';
|
|
15
15
|
import { SuggestionEngine } from './suggestions.js';
|
|
16
16
|
import { buildTextToolProtocolDirective, extractTopLevelJsonObjects, MALFORMED_TOOL_CALL_FEEDBACK, parseTextToolCallsFromContent, stripToolCallBlocks } from './textToolProtocol.js';
|
|
17
|
-
import { DynamicToolRouter } from './toolRouter.js';
|
|
17
|
+
import { DynamicToolRouter, calculateSearchEscalationScore } from './toolRouter.js';
|
|
18
18
|
import { executeTool, prepareToolArguments, toolsSchema, isBuiltinTool } from './tools.js';
|
|
19
19
|
import { detectAmbiguities, isQueryTooVague, emitClarifyingQuestions, calculateConfidence, generateClarifyingQuestions, buildClarificationContext } from './clarifyingQuestions.js';
|
|
20
20
|
import { ClarificationAnalytics, ClarificationConfig } from './clarificationAnalytics.js';
|
|
21
21
|
import { calculateTokenCost } from './telemetry.js';
|
|
22
22
|
import { extractCitations, resolveCitationReference } from './citations.js';
|
|
23
|
-
import { resolveQueryEntities } from './catalogEntityResolver.js';
|
|
23
|
+
import { resolveQueryEntities, isQueryInDomain, classifyQueryDomain } from './catalogEntityResolver.js';
|
|
24
24
|
import { TokenTracker } from './tokenTracker.js';
|
|
25
25
|
import { RoutingInterceptor } from './routingInterceptor.js';
|
|
26
26
|
|
|
@@ -327,17 +327,18 @@ export class KikuAgent {
|
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (hasPriorClarification) {
|
|
330
|
+
|
|
331
|
+
if (query.includes('[SYSTEM CLARIFICATION]') || query.includes('CLARIFICATION:')) {
|
|
333
332
|
return null;
|
|
334
333
|
}
|
|
335
334
|
|
|
336
|
-
|
|
335
|
+
const lastUserMsg = this.conversationHistory?.slice().reverse().find(m => m.role === 'user');
|
|
336
|
+
const wasLastTurnClarified = lastUserMsg?.content && (lastUserMsg.content.includes('[SYSTEM CLARIFICATION]') || lastUserMsg.content.includes('CLARIFICATION:'));
|
|
337
|
+
if (wasLastTurnClarified) {
|
|
337
338
|
return null;
|
|
338
339
|
}
|
|
339
340
|
|
|
340
|
-
if (
|
|
341
|
+
if (isQueryTooVague(query)) {
|
|
341
342
|
return null;
|
|
342
343
|
}
|
|
343
344
|
|
|
@@ -345,8 +346,7 @@ export class KikuAgent {
|
|
|
345
346
|
const confidence = calculateConfidence(query, ambiguities);
|
|
346
347
|
const threshold = clarifyConfig.confidenceThreshold;
|
|
347
348
|
|
|
348
|
-
|
|
349
|
-
const CROSS_CATEGORY_PRIORITIES = ['media_type', 'career_phase', 'specific_work', 'timeframe', 'comparison'];
|
|
349
|
+
const CROSS_CATEGORY_PRIORITIES = ['media_type', 'career_phase', 'specific_work', 'timeframe', 'comparison', 'scope', 'aspect_focus', 'depth'];
|
|
350
350
|
const highImpactAmbiguities = ambiguities.filter(a => CROSS_CATEGORY_PRIORITIES.includes(a.category));
|
|
351
351
|
|
|
352
352
|
const shouldAsk = (confidence.score < threshold || confidence.shouldAsk) && highImpactAmbiguities.length > 0;
|
|
@@ -714,8 +714,12 @@ export class KikuAgent {
|
|
|
714
714
|
* the limit, replace the oldest tool results with omission stubs — tool
|
|
715
715
|
* payloads are the bulkiest and least-likely-to-be-reused part of history.
|
|
716
716
|
*/
|
|
717
|
-
_enforceContextBudget() {
|
|
718
|
-
const
|
|
717
|
+
_enforceContextBudget(limitOverride) {
|
|
718
|
+
const envLimit = Number(process.env.KIKU_CONTEXT_LIMIT);
|
|
719
|
+
const override = Number(limitOverride);
|
|
720
|
+
const rawLimit = (Number.isFinite(override) && override > 0)
|
|
721
|
+
? override
|
|
722
|
+
: envLimit;
|
|
719
723
|
if (!Number.isFinite(rawLimit) || rawLimit <= 0) return false;
|
|
720
724
|
const budget = Math.floor(rawLimit * 0.85);
|
|
721
725
|
|
|
@@ -740,6 +744,7 @@ export class KikuAgent {
|
|
|
740
744
|
if (total <= budget) break;
|
|
741
745
|
if (msg.role !== 'tool' || msg._omittedForContext) continue;
|
|
742
746
|
const prev = msg._tokenEstimate || estimateTokenCount([msg]);
|
|
747
|
+
if (prev <= omittedTokens) continue;
|
|
743
748
|
total -= prev - omittedTokens;
|
|
744
749
|
msg.content = omitted;
|
|
745
750
|
msg._omittedForContext = true;
|
|
@@ -817,10 +822,10 @@ export class KikuAgent {
|
|
|
817
822
|
return results;
|
|
818
823
|
}
|
|
819
824
|
|
|
820
|
-
buildSystemPrompt(scopedTools = null) {
|
|
825
|
+
buildSystemPrompt(scopedTools = null, options = {}) {
|
|
821
826
|
const allTools = this.getAllToolsSchema ? this.getAllToolsSchema() : [];
|
|
822
827
|
const activeTools = scopedTools || allTools;
|
|
823
|
-
return buildSystemPrompt(activeTools, { isNativeToolCalling: true });
|
|
828
|
+
return buildSystemPrompt(activeTools, { isNativeToolCalling: true, ...options });
|
|
824
829
|
}
|
|
825
830
|
|
|
826
831
|
_extractTextToolCalls(content) {
|
|
@@ -863,9 +868,22 @@ export class KikuAgent {
|
|
|
863
868
|
onError = () => { },
|
|
864
869
|
onNotice = () => { },
|
|
865
870
|
systemDirectives = null,
|
|
866
|
-
signal = null
|
|
871
|
+
signal = null,
|
|
872
|
+
temperature = undefined,
|
|
873
|
+
topP = undefined,
|
|
874
|
+
contextLimit = undefined,
|
|
875
|
+
minP = undefined,
|
|
876
|
+
repeatPenalty = undefined
|
|
867
877
|
} = callbacks;
|
|
868
878
|
|
|
879
|
+
const _num = (v) => Number.isFinite(Number(v)) ? Number(v) : undefined;
|
|
880
|
+
const runTemperature = _num(temperature) !== undefined ? Math.min(2, Math.max(0, _num(temperature))) : undefined;
|
|
881
|
+
const runTopP = _num(topP) !== undefined ? Math.min(1, Math.max(0.01, _num(topP))) : undefined;
|
|
882
|
+
const runMinP = _num(minP) !== undefined ? Math.min(1, Math.max(0, _num(minP))) : undefined;
|
|
883
|
+
const runRepeatPenalty = _num(repeatPenalty) !== undefined ? Math.min(2, Math.max(1, _num(repeatPenalty))) : undefined;
|
|
884
|
+
const _ctx = Math.floor(Number(contextLimit));
|
|
885
|
+
const runContextLimit = Number.isFinite(_ctx) && _ctx >= 1024 ? Math.min(_ctx, 1000000) : undefined;
|
|
886
|
+
|
|
869
887
|
const queryStartTime = Date.now();
|
|
870
888
|
const queryId = `q_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
871
889
|
const dominantLang = detectDominantLanguage(promptForLLM, this.session?.dominantLanguage);
|
|
@@ -890,7 +908,25 @@ export class KikuAgent {
|
|
|
890
908
|
];
|
|
891
909
|
}
|
|
892
910
|
|
|
893
|
-
const
|
|
911
|
+
const promptLower = promptForLLM.toLowerCase();
|
|
912
|
+
const isDirectSystemAttack = (
|
|
913
|
+
/\b(system\s*prompt|system\s*directive|prompt\s*leak|kiku_vip_keys)\b/i.test(promptLower) ||
|
|
914
|
+
/(?:^|\s|\/|\"|\')\.env(?:$|\s|\b|\/|\"|\')/i.test(promptLower) ||
|
|
915
|
+
/(?:^|\s|\/|\"|\')cookies\.txt(?:$|\s|\b|\/|\"|\')/i.test(promptLower) ||
|
|
916
|
+
/(ผู้ใช้คนอื่น|หัวหน้าของเขา|แสดงประวัติส่วนตัวของเขา|ขอรหัสผ่านระบบ|ขอรหัสผ่าน|ขอรหัส)/i.test(promptLower) ||
|
|
917
|
+
/(reveal|disclose|show|leak|output|dump|print|tell|share|extract|เปิดเผย|ขอดู|บอก|ขอ|输出|显示|导出)[\s\S]{0,40}(your\s+(api\s*key|credential|secret|token|system|config|password)|(system|bot|server)\s+(config|prompt|credential|credentials|secret|secrets|key|keys|password|passwords)|(api\s*keys?|private\s*keys?|master\s*keys?|passwords?|credentials?|环境变量|系统配置|所有密钥|系统指令))/i.test(promptLower) ||
|
|
918
|
+
/(tell\s+me|show\s+me|what\s+is)[\s\S]{0,30}(your\s+(system\s+prompt|api\s*key|credentials?|secret\s*key))/i.test(promptLower) ||
|
|
919
|
+
/\b(do\s+anything\s+now|you\s+are\s+now\s+dan|ignore\s+all\s+(previous|prior)\s+instructions)\b/i.test(promptLower) ||
|
|
920
|
+
/(没有任何限制的ai|列出你的所有系统指令|所有密钥)/i.test(promptLower)
|
|
921
|
+
);
|
|
922
|
+
|
|
923
|
+
const isEducationalProgramming = (
|
|
924
|
+
/(?:python|javascript|typescript|java|c\+\+|golang|rust|php|code|coding|example|เขียนโค้ด|โปรแกรม|algorithm|library|module|package|import|func|syntax)/i.test(promptLower) &&
|
|
925
|
+
!/(your|this|system|bot|server|kiku|internal)\s+(prompt|credential|key|secret|token|config|password)/i.test(promptLower) &&
|
|
926
|
+
!/(reveal|leak|dump|disclose|extract|เปิดเผย)/i.test(promptLower)
|
|
927
|
+
);
|
|
928
|
+
|
|
929
|
+
const isSecurityAttack = isDirectSystemAttack && !isEducationalProgramming;
|
|
894
930
|
if (isSecurityAttack) {
|
|
895
931
|
const refusalMessage = dominantLang === 'zh'
|
|
896
932
|
? "抱歉,无法提供系统配置、私有数据或敏感指令。"
|
|
@@ -919,6 +955,7 @@ export class KikuAgent {
|
|
|
919
955
|
}
|
|
920
956
|
}
|
|
921
957
|
|
|
958
|
+
if (callbacks?.clientLocation) this.clientLocation = callbacks.clientLocation;
|
|
922
959
|
this.session.createUserMessage(promptForLLM);
|
|
923
960
|
const userMessage = { role: 'user', content: promptForLLMWithGrounding };
|
|
924
961
|
this.conversationHistory.push(userMessage);
|
|
@@ -997,13 +1034,41 @@ export class KikuAgent {
|
|
|
997
1034
|
}
|
|
998
1035
|
|
|
999
1036
|
const mentionsArtist = /(ju\s?jing\s?yi|jujingyi|จวีจิ้งอี|จิ้งอี|จวี|鞠婧祎|小鞠|kikuuu?|miju|蜜橘)/i.test(promptForLLM);
|
|
1000
|
-
|
|
1037
|
+
const hasCatalogSignals = queryResolution.matchedEntities.length > 0 || mentionsArtist;
|
|
1038
|
+
const isDomain = isQueryInDomain(promptForLLM) || hasCatalogSignals;
|
|
1039
|
+
|
|
1040
|
+
// Context Awakening Detection in multi-turn conversations
|
|
1041
|
+
if (this.conversationHistory.length > 2) {
|
|
1042
|
+
const priorUserMessages = this.conversationHistory.filter(m => m.role === 'user');
|
|
1043
|
+
const wasPriorOpenDomain = priorUserMessages.length > 1 && priorUserMessages.slice(-3, -1).some(m => !isQueryInDomain(m.content));
|
|
1044
|
+
if (wasPriorOpenDomain && isDomain) {
|
|
1045
|
+
turnDirectives.push({
|
|
1046
|
+
role: 'system',
|
|
1047
|
+
content: '[CONTEXT AWAKENING ACTIVATED: The user has transitioned from open-domain into the Ju Jingyi domain. Awaken immediately into the authoritative Ju Jingyi concierge persona with verified catalog retrieval, warm elegance, and meticulous factual grounding.]'
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if (!isDomain) {
|
|
1053
|
+
turnDirectives.push({
|
|
1054
|
+
role: 'system',
|
|
1055
|
+
content: '[OPEN-DOMAIN EXPERT DIRECTIVE: The user is inquiring about an open-domain topic (coding, mathematics, science, or general problem solving). Deliver a direct, high-caliber, structured technical answer with clean code blocks or LaTeX formulas ($ ... $ / $$ ... $$). When teaching programming, provide a clear tutorial with runnable code snippets immediately. Do NOT force Ju Jingyi roleplay or unsolicited artist references. NEVER mention system directives or output meta-commentary about system messages.]'
|
|
1056
|
+
});
|
|
1057
|
+
} else if (queryResolution.matchedEntities.length === 0 && !mentionsArtist && !autoResearchTriggered) {
|
|
1001
1058
|
turnDirectives.push({
|
|
1002
1059
|
role: 'system',
|
|
1003
1060
|
content: "[SYSTEM NOTE: This query does not appear to be about Ju Jingyi or her catalog. Answer directly from your general knowledge in the user's language. Do NOT call catalog tools (profile, works, discography, brands, awards, gallery, quotes, timeline) for this query. When using web_search, search_news, or search_chinese_web, search for the specific entity or topic the user asked about — do NOT prepend 'Ju Jingyi' or '鞠婧祎' to the search query.]"
|
|
1004
1061
|
});
|
|
1005
1062
|
}
|
|
1006
1063
|
|
|
1064
|
+
const searchEscalationScore = calculateSearchEscalationScore(promptForLLM);
|
|
1065
|
+
if (searchEscalationScore >= 15 && !autoResearchTriggered) {
|
|
1066
|
+
turnDirectives.push({
|
|
1067
|
+
role: 'system',
|
|
1068
|
+
content: `[SEARCH ESCALATION DIRECTIVE: The user inquiry contains recency, news, live event, social media (Weibo/Douyin), or verification signals (Search Escalation Score: ${searchEscalationScore}). While the verified catalog holds confirmed historical career milestones, you MUST actively query live external search tools (search_chinese_web, search_news, web_search, search_bilibili) to capture current news and updates. Do NOT conclude that information is missing without searching external tools first.]`
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1007
1072
|
const clarifyingResult = await this._handleClarifyingQuestions(
|
|
1008
1073
|
promptForLLM,
|
|
1009
1074
|
dominantLang,
|
|
@@ -1049,6 +1114,17 @@ export class KikuAgent {
|
|
|
1049
1114
|
this._activeToolSchema = activeTools;
|
|
1050
1115
|
const activeToolNames = new Set(activeTools.map(t => t.function?.name).filter(Boolean));
|
|
1051
1116
|
|
|
1117
|
+
const activeDomain = isDomain ? 'IN_DOMAIN' : 'OPEN_DOMAIN';
|
|
1118
|
+
const effectiveSystemPrompt = this.buildSystemPrompt(activeTools, {
|
|
1119
|
+
domain: activeDomain,
|
|
1120
|
+
inDomain: isDomain,
|
|
1121
|
+
query: promptForLLM,
|
|
1122
|
+
});
|
|
1123
|
+
this.conversationHistory[0] = {
|
|
1124
|
+
role: 'system',
|
|
1125
|
+
content: effectiveSystemPrompt + memoryContext,
|
|
1126
|
+
};
|
|
1127
|
+
|
|
1052
1128
|
while (currentIteration < this.maxIterations) {
|
|
1053
1129
|
if (signal?.aborted) {
|
|
1054
1130
|
this.stateMachine.reset();
|
|
@@ -1061,7 +1137,7 @@ export class KikuAgent {
|
|
|
1061
1137
|
if (currentIteration > 1) {
|
|
1062
1138
|
await this.applySlidingWindow();
|
|
1063
1139
|
}
|
|
1064
|
-
this._enforceContextBudget();
|
|
1140
|
+
this._enforceContextBudget(runContextLimit);
|
|
1065
1141
|
|
|
1066
1142
|
let assistantMessage = null;
|
|
1067
1143
|
let isReasoning = false;
|
|
@@ -1077,8 +1153,12 @@ export class KikuAgent {
|
|
|
1077
1153
|
assistantMessage = await this.client.chat({
|
|
1078
1154
|
messages: chatMessages,
|
|
1079
1155
|
tools: activeTools,
|
|
1080
|
-
temperature: 0.3,
|
|
1156
|
+
temperature: runTemperature ?? 0.3,
|
|
1157
|
+
topP: runTopP ?? null,
|
|
1158
|
+
minP: runMinP,
|
|
1159
|
+
repeatPenalty: runRepeatPenalty,
|
|
1081
1160
|
maxTokens: OUTPUT_TOKEN_BUDGET,
|
|
1161
|
+
contextLimit: runContextLimit,
|
|
1082
1162
|
stream: true,
|
|
1083
1163
|
signal,
|
|
1084
1164
|
onThought: (thoughtChunk) => {
|
|
@@ -1177,15 +1257,27 @@ export class KikuAgent {
|
|
|
1177
1257
|
|
|
1178
1258
|
if (currentIteration === 1 && recordedTools.length === 0) {
|
|
1179
1259
|
const content = String(assistantMessage.content || '');
|
|
1180
|
-
const refusalRegex = /(ไม่มี(การ)?บันทึก|ไม่มี(อยู่ใน)
|
|
1181
|
-
const
|
|
1182
|
-
const
|
|
1183
|
-
|
|
1260
|
+
const refusalRegex = /(ไม่มี(การ)?บันทึก|ไม่มี(อยู่ใน)?ระบบ|ไม่มีข้อมูล|ไม่มีรายละเอียด|ไม่พบ(?:ข้อมูล|บันทึก|ผลงาน|รายการ|รายละเอียด|หลักฐาน)|ข้อมูลทางธุรกิจ|ข้อมูลธุรกิจ|ข้อมูลเชิงพาณิชย์|ความลับทางการค้า|ความลับเชิงพาณิชย์|ปรัชญาการทำงาน|ตัวตนของฉัน|นอกเหนือขอบเขต|ไม่สามารถระบุ|ไม่ได้ระบุ|not found|no verified record|no record|could not find|unable to find|outside the scope|confidential|internal business|trade secret|business secret|commercial secret|proprietary|internal statistics?|operational philosophy|my own mindset|without querying|没有找到|未找到|暂无|没有记录|无法查询|商业机密|内部数据|机密)/i;
|
|
1261
|
+
const isNegation = /(?:ไม่(?:ใช่|ถือเป็น)?(?:ความลับ|เรื่องลับ)|not\s+(?:a\s+)?(?:secret|confidential|trade\s*secret)|ไม่ใช่ข้อมูลธุรกิจ|ไม่ได้เป็นความลับ)/i.test(content);
|
|
1262
|
+
const isNegativeFactualQuery = /(?:ข่าวลือ|คดี|ทำผิด|เรื่องอื้อฉาว|เสียหาย|แต่งงาน|แฟน(?!คลับ)|สามี|scandal|rumor|arrest|crime|lawsuit|negative)/i.test(promptForLLM);
|
|
1263
|
+
const isSubstantiveAnswer = content.length > 100 && /(?:จวีจิ้งอี|Ju Jingyi|鞠婧祎|ซีรีส์|ผลงาน|เพลง|ละคร|บทบาท|ศิลปิน|นักแสดง|รางวัล)/i.test(content);
|
|
1264
|
+
const isRefusal = refusalRegex.test(content) && !isNegation && !isNegativeFactualQuery && !isSubstantiveAnswer;
|
|
1265
|
+
const isSec = /(ผู้ใช้คนอื่น|หัวหน้าของเขา|รหัสผ่าน|ความลับของระบบ|\bpassword\b|\bsecret\b|\bcredential\b|\baccess.token\b|\.env|cookies\.txt|kiku_vip_keys|system\s+directive|mcp\s+directive|bypass|unauthorized)/i.test(promptForLLM);
|
|
1266
|
+
const inDomain = isQueryInDomain(promptForLLM);
|
|
1267
|
+
const isImageAttachment = /\[USER ATTACHMENT:[^\]]*(?:รูปภาพ|image)/i.test(promptForLLM);
|
|
1268
|
+
const isVisionLimitation = isImageAttachment && /(?:ภาพ|รูป|รูปภาพ|ไฟล์ภาพ|photo|image|picture|มองไม่เห็น|ดูรูปไม่ได้|ไม่สามารถดูภาพ|เปิดดูภาพไม่ได้|วิเคราะห์ภาพโดยตรงไม่ได้|ระบบข้อความ)/i.test(content);
|
|
1269
|
+
if (isRefusal && !isSec && inDomain && !isVisionLimitation) {
|
|
1270
|
+
const dynamicSuggested = (this.router?.routeToolsForQuery(promptForLLM) || [])
|
|
1271
|
+
.slice(0, 5)
|
|
1272
|
+
.map(t => t.function?.name || t.name)
|
|
1273
|
+
.filter(Boolean)
|
|
1274
|
+
.join(', ') || 'search_works, search_discography, get_brand_endorsements, get_career_timeline';
|
|
1275
|
+
|
|
1184
1276
|
this.conversationHistory.pop();
|
|
1185
1277
|
if (currentAssistantSessionMsg) currentAssistantSessionMsg.parts = [];
|
|
1186
1278
|
this.conversationHistory.push({
|
|
1187
1279
|
role: 'user',
|
|
1188
|
-
content:
|
|
1280
|
+
content: `[MANDATORY RETRIEVAL RULE & VERIFICATION CONSTRAINT] You are strictly FORBIDDEN from asserting that information does not exist, is confidential, or is missing without querying a tool first in this turn. Call the appropriate tool (e.g. ${dynamicSuggested}) NOW to fetch and verify the facts before answering.`
|
|
1189
1281
|
});
|
|
1190
1282
|
continue;
|
|
1191
1283
|
}
|
|
@@ -1194,10 +1286,10 @@ export class KikuAgent {
|
|
|
1194
1286
|
const isExplicitCatalogMention = explicitCatalogRegex.test(promptForLLM);
|
|
1195
1287
|
const hasCatalogTarget = (queryResolution?.recommendedTools?.length > 0 || queryResolution?.matchedEntities?.length > 0 || isExplicitCatalogMention) && (mentionsArtist || isExplicitCatalogMention);
|
|
1196
1288
|
|
|
1197
|
-
if (!isSec && hasCatalogTarget) {
|
|
1289
|
+
if (!isSec && hasCatalogTarget && !isVisionLimitation) {
|
|
1198
1290
|
const suggestedTools = queryResolution?.recommendedTools?.length > 0
|
|
1199
1291
|
? queryResolution.recommendedTools.join(', ')
|
|
1200
|
-
: 'search_works, search_discography, get_brand_endorsements
|
|
1292
|
+
: ((this.router?.routeToolsForQuery(promptForLLM) || []).slice(0, 5).map(t => t.function?.name || t.name).join(', ') || 'search_works, search_discography, get_brand_endorsements');
|
|
1201
1293
|
this.conversationHistory.pop();
|
|
1202
1294
|
if (currentAssistantSessionMsg) currentAssistantSessionMsg.parts = [];
|
|
1203
1295
|
this.conversationHistory.push({
|
|
@@ -1206,6 +1298,18 @@ export class KikuAgent {
|
|
|
1206
1298
|
});
|
|
1207
1299
|
continue;
|
|
1208
1300
|
}
|
|
1301
|
+
|
|
1302
|
+
const isWeatherQuery = /(?:สภาพอากาศ|พยากรณ์อากาศ|อากาศ|ฝนตก|อุณหภูมิ|กี่องศา|weather|forecast|temperature|rain|แถวนี้|ใกล้ฉัน|ที่นี่)/i.test(promptForLLM);
|
|
1303
|
+
const isLocationDisclaimer = /(?:ไม่ทราบพิกัด|ไม่ทราบตำแหน่ง|ไม่ทราบที่ตั้ง|ไม่รู้ตำแหน่ง|ระบุสถานที่|ระบุพิกัด|ระบุตำแหน่ง|ขออนุญาตดึงตำแหน่ง|จะแสดงผลหลังจาก|รอดึงตำแหน่ง|รอข้อมูลตำแหน่ง|ดึงตำแหน่งปัจจุบันก่อน|don't know (?:your )?location|unknown location|specify (?:your )?location|provide (?:your )?location)/i.test(content);
|
|
1304
|
+
if (isWeatherQuery && isLocationDisclaimer && !isSec) {
|
|
1305
|
+
this.conversationHistory.pop();
|
|
1306
|
+
if (currentAssistantSessionMsg) currentAssistantSessionMsg.parts = [];
|
|
1307
|
+
this.conversationHistory.push({
|
|
1308
|
+
role: 'user',
|
|
1309
|
+
content: '[MANDATORY TOOL CALL: get_weather] You must NOT defer answering, ask for user device permission, or state that weather will be displayed later. Call the tool get_weather (passing the named destination if one was specified) NOW and present the real-time weather metrics (temperature, condition, humidity, wind) and map pin immediately to the user.'
|
|
1310
|
+
});
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1209
1313
|
}
|
|
1210
1314
|
|
|
1211
1315
|
const needProtocol = Boolean(this.client?.toolsDisabledReason) && !textProtocolTaught;
|
|
@@ -1229,13 +1333,25 @@ export class KikuAgent {
|
|
|
1229
1333
|
const totalDurationMs = Date.now() - queryStartTime;
|
|
1230
1334
|
this.session.stats.totalDurationMs += totalDurationMs;
|
|
1231
1335
|
|
|
1232
|
-
const
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1336
|
+
const hasImageAttachment = /\[USER ATTACHMENT:[^\]]*(?:รูปภาพ|image)/i.test(promptForLLM);
|
|
1337
|
+
const imageFallbackAnswer = dominantLang === 'zh'
|
|
1338
|
+
? "已收到您的图片。由于当前系统主要为文本与作品资料库分析,暂不支持直接解析图像像素。您可以告诉我关于这张图片的剧名、角色、活动或想查询的内容,我很乐意为您检索相关资料与写真哦。"
|
|
1339
|
+
: dominantLang === 'en'
|
|
1340
|
+
? "I received your image attachment. Currently, the system focuses on text and catalog intelligence and cannot directly inspect image pixels. Feel free to tell me the drama name, character, event, or what you'd like to look up about this photo, and I'll gladly retrieve the verified catalog details and gallery stills for you."
|
|
1341
|
+
: "ได้รับรูปภาพเรียบร้อยแล้วค่ะ แต่เนื่องจากระบบปัจจุบันเน้นการวิเคราะห์ข้อมูลและแคตตาล็อกเป็นหลัก จึงยังไม่รองรับการวิเคราะห์พิกเซลภาพโดยตรง คุณสามารถพิมพ์บอกชื่อผลงาน ละคร ลุคงาน หรือสิ่งที่ต้องการค้นหาเกี่ยวกับภาพนี้ เพื่อให้ฉันช่วยค้นหาข้อมูลและรูปภาพจากคลังข้อมูลได้เลยนะคะ";
|
|
1342
|
+
|
|
1343
|
+
const fallbackAnswer = hasImageAttachment
|
|
1344
|
+
? imageFallbackAnswer
|
|
1345
|
+
: (
|
|
1346
|
+
dominantLang === 'zh' ? "抱歉,无法处理您的回答。" :
|
|
1347
|
+
dominantLang === 'ja' ? "申し訳ありません、回答を処理できませんでした。" :
|
|
1348
|
+
dominantLang === 'ko' ? "죄송합니다. 답변을 처리할 수 없습니다." :
|
|
1349
|
+
dominantLang === 'en' ? "Sorry, unable to process a response." :
|
|
1350
|
+
"ขออภัยค่ะ ไม่สามารถประมวลผลคำตอบได้"
|
|
1351
|
+
);
|
|
1352
|
+
|
|
1353
|
+
const rawAnswerContent = stripToolCallBlocks(assistantMessage.content || fallbackAnswer);
|
|
1354
|
+
const finalAnswer = sanitizeResponse(rawAnswerContent);
|
|
1239
1355
|
historyMessage.content = finalAnswer;
|
|
1240
1356
|
this.conversationHistory = this.conversationHistory.filter(m =>
|
|
1241
1357
|
!(typeof m?.content === 'string' && m.content.includes('[MANDATORY'))
|
|
@@ -1367,11 +1483,18 @@ export class KikuAgent {
|
|
|
1367
1483
|
if (cachedResult) {
|
|
1368
1484
|
result = { ...cachedResult, cache: { hit: true, reason: 'duplicate_call_in_query' } };
|
|
1369
1485
|
} else if (isBuiltin) {
|
|
1370
|
-
result = await executeTool(toolName, finalArgs, { agent: this, memory: this.memory, client: this.client, signal, onSubagentProgress });
|
|
1486
|
+
result = await executeTool(toolName, finalArgs, { agent: this, memory: this.memory, client: this.client, signal, onSubagentProgress, clientLocation: callbacks?.clientLocation || this.clientLocation });
|
|
1371
1487
|
} else if (isMcp) {
|
|
1372
|
-
|
|
1488
|
+
try {
|
|
1489
|
+
result = await this.mcpManager.callTool(toolName, finalArgs);
|
|
1490
|
+
} catch (err) {
|
|
1491
|
+
result = {
|
|
1492
|
+
status: 'error',
|
|
1493
|
+
message: `Failed executing MCP tool "${toolName}": ${err.message}`
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1373
1496
|
} else {
|
|
1374
|
-
result = await executeTool(toolName, finalArgs, { agent: this, memory: this.memory, client: this.client, signal, onSubagentProgress });
|
|
1497
|
+
result = await executeTool(toolName, finalArgs, { agent: this, memory: this.memory, client: this.client, signal, onSubagentProgress, clientLocation: callbacks?.clientLocation || this.clientLocation });
|
|
1375
1498
|
}
|
|
1376
1499
|
|
|
1377
1500
|
if (!cachedResult) toolResultCache.set(signature, result);
|
|
@@ -1383,6 +1506,127 @@ export class KikuAgent {
|
|
|
1383
1506
|
|
|
1384
1507
|
this._extractFactsFromToolResult(toolName, finalArgs, result);
|
|
1385
1508
|
|
|
1509
|
+
const isNotFoundResult = Boolean(
|
|
1510
|
+
result && (
|
|
1511
|
+
result.status === 'not_found' ||
|
|
1512
|
+
result.status === 'no_results' ||
|
|
1513
|
+
result.count === 0 ||
|
|
1514
|
+
result.returnedCount === 0 ||
|
|
1515
|
+
(Array.isArray(result.photos) && result.photos.length === 0) ||
|
|
1516
|
+
(Array.isArray(result.works) && result.works.length === 0) ||
|
|
1517
|
+
(Array.isArray(result.songs) && result.songs.length === 0) ||
|
|
1518
|
+
(Array.isArray(result.awards) && result.awards.length === 0) ||
|
|
1519
|
+
(Array.isArray(result.brands) && result.brands.length === 0) ||
|
|
1520
|
+
(typeof result.message === 'string' && /No matching (?:data|photos|works|awards|discography|items) found in local catalog|ไม่พบข้อมูล/i.test(result.message))
|
|
1521
|
+
)
|
|
1522
|
+
);
|
|
1523
|
+
|
|
1524
|
+
const CATALOG_SEARCH_TOOLS = new Set([
|
|
1525
|
+
'get_gallery_photos',
|
|
1526
|
+
'search_works',
|
|
1527
|
+
'search_discography',
|
|
1528
|
+
'get_awards',
|
|
1529
|
+
'get_brand_endorsements',
|
|
1530
|
+
'get_career_timeline',
|
|
1531
|
+
'get_work_detail',
|
|
1532
|
+
'get_song_detail',
|
|
1533
|
+
'get_quotes',
|
|
1534
|
+
'get_profile_and_fandom'
|
|
1535
|
+
]);
|
|
1536
|
+
|
|
1537
|
+
const isSec = /(ผู้ใช้คนอื่น|หัวหน้าของเขา|รหัสผ่าน|ความลับของระบบ|\bpassword\b|\bsecret\b|\bcredential\b|\baccess.token\b|\.env|cookies\.txt|kiku_vip_keys|system\s+directive|mcp\s+directive|bypass|unauthorized)/i.test(promptForLLM);
|
|
1538
|
+
const forbidExternal = /(?:เฉพาะใน|ห้ามค้นเว็บ|ห้ามค้นเน็ต|only\s+in\s+catalog|catalog\s+only|no\s+web)/i.test(promptForLLM);
|
|
1539
|
+
|
|
1540
|
+
if (isNotFoundResult && CATALOG_SEARCH_TOOLS.has(toolName) && !isSec && !forbidExternal && !signal?.aborted && !result._escalated) {
|
|
1541
|
+
const isImageQuery = toolName === 'get_gallery_photos' ||
|
|
1542
|
+
/(?:รูป|ภาพ|รูปภาพ|ภาพถ่าย|โปสเตอร์|สติลล์|concept\s*art|stills?|photo|image|picture|poster|剧照|概念图|写真)/i.test(promptForLLM) ||
|
|
1543
|
+
/(?:รูป|ภาพ|concept\s*art|stills?|photo|image|剧照|概念图)/i.test(finalArgs?.query || '');
|
|
1544
|
+
const isChineseQuery = /[\u4E00-\u9FA5]/.test(promptForLLM) || /[\u4E00-\u9FA5]/.test(finalArgs?.query || '');
|
|
1545
|
+
const isNewsQuery = /(?:ข่าว|ล่าสุด|วันนี้|อัปเดต|เมื่อวาน|สัปดาห์นี้|news|latest|recent|update|最新|新闻)/i.test(promptForLLM);
|
|
1546
|
+
|
|
1547
|
+
const rawQuery = finalArgs?.query || finalArgs?.keywords || finalArgs?.title || finalArgs?.workIdOrTitle || promptForLLM;
|
|
1548
|
+
let cleanQuery = String(rawQuery).replace(/\[USER ATTACHMENT:[^\]]*\]/gi, '').trim();
|
|
1549
|
+
if (!/(?:จวีจิ้งอี|Ju\s*Jingyi|鞠婧祎|Kiku)/i.test(cleanQuery)) {
|
|
1550
|
+
cleanQuery = `鞠婧祎 ${cleanQuery}`.trim();
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
let fallbackToolName = 'web_search';
|
|
1554
|
+
let fallbackArgs = { keywords: cleanQuery, target_language: isChineseQuery ? 'zh' : 'th' };
|
|
1555
|
+
|
|
1556
|
+
if (isImageQuery && (activeToolNames.has('search_web_images') || isBuiltinTool('search_web_images'))) {
|
|
1557
|
+
fallbackToolName = 'search_web_images';
|
|
1558
|
+
fallbackArgs = { keywords: cleanQuery, target_language: isChineseQuery ? 'zh' : 'th' };
|
|
1559
|
+
} else if (isNewsQuery && (activeToolNames.has('search_news') || isBuiltinTool('search_news'))) {
|
|
1560
|
+
fallbackToolName = 'search_news';
|
|
1561
|
+
fallbackArgs = { keywords: cleanQuery, target_language: isChineseQuery ? 'zh' : 'th' };
|
|
1562
|
+
} else if (isChineseQuery && (activeToolNames.has('search_chinese_web') || isBuiltinTool('search_chinese_web'))) {
|
|
1563
|
+
fallbackToolName = 'search_chinese_web';
|
|
1564
|
+
fallbackArgs = { keywords: cleanQuery, target_language: 'zh' };
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
if (activeToolNames.has(fallbackToolName) || isBuiltinTool(fallbackToolName)) {
|
|
1568
|
+
activeToolNames.add(fallbackToolName);
|
|
1569
|
+
if (typeof callbacks?.onToolRemove === 'function') {
|
|
1570
|
+
callbacks.onToolRemove(toolName);
|
|
1571
|
+
}
|
|
1572
|
+
try {
|
|
1573
|
+
onNotice(`ไม่พบข้อมูลในแค็ตตาล็อกสำหรับ "${toolName}" → สลับไปยังเครื่องมือค้นหาภายนอกอินเทอร์เน็ต (${fallbackToolName})...`);
|
|
1574
|
+
} catch { }
|
|
1575
|
+
eventBus.emit(Events.AGENT_TOOL_ESCALATED, { queryId, fromTool: toolName, toTool: fallbackToolName });
|
|
1576
|
+
|
|
1577
|
+
const preparedFallback = prepareToolArguments(fallbackToolName, fallbackArgs);
|
|
1578
|
+
const finalFallbackArgs = preparedFallback.safe ? preparedFallback.args : fallbackArgs;
|
|
1579
|
+
|
|
1580
|
+
this.stateMachine.transition(AgentStates.FETCHING_TOOL, { toolName: fallbackToolName });
|
|
1581
|
+
const fbToolPart = this.session.addToolPart(currentAssistantSessionMsg, fallbackToolName, finalFallbackArgs);
|
|
1582
|
+
onToolStart(fallbackToolName, finalFallbackArgs);
|
|
1583
|
+
eventBus.emit(Events.AGENT_TOOL_START, { queryId, toolName: fallbackToolName, args: finalFallbackArgs });
|
|
1584
|
+
|
|
1585
|
+
const fbStartTime = Date.now();
|
|
1586
|
+
const fallbackResult = await executeTool(fallbackToolName, finalFallbackArgs, {
|
|
1587
|
+
agent: this,
|
|
1588
|
+
memory: this.memory,
|
|
1589
|
+
client: this.client,
|
|
1590
|
+
signal,
|
|
1591
|
+
onSubagentProgress,
|
|
1592
|
+
clientLocation: callbacks?.clientLocation || this.clientLocation
|
|
1593
|
+
});
|
|
1594
|
+
const fbDurationMs = Date.now() - fbStartTime;
|
|
1595
|
+
|
|
1596
|
+
this.session.finalizeToolPart(currentAssistantSessionMsg, fbToolPart.id, fallbackResult);
|
|
1597
|
+
onToolResult(fallbackToolName, fallbackResult, fbDurationMs);
|
|
1598
|
+
eventBus.emit(Events.AGENT_TOOL_RESULT, { queryId, toolName: fallbackToolName, result: fallbackResult, durationMs: fbDurationMs });
|
|
1599
|
+
|
|
1600
|
+
this._extractFactsFromToolResult(fallbackToolName, finalFallbackArgs, fallbackResult);
|
|
1601
|
+
|
|
1602
|
+
toolResultTracker.total++;
|
|
1603
|
+
toolResultTracker.toolNames.push(fallbackToolName);
|
|
1604
|
+
if (fallbackResult.status === 'not_found') toolResultTracker.notFound++;
|
|
1605
|
+
else if (fallbackResult.status === 'error') toolResultTracker.error++;
|
|
1606
|
+
else toolResultTracker.success++;
|
|
1607
|
+
|
|
1608
|
+
const cappedFallback = this._capToolResultForHistory(fallbackResult);
|
|
1609
|
+
const fallbackInstruction = 'Use the external internet search results above to answer the user query with verified information, media references, and rich detail.';
|
|
1610
|
+
|
|
1611
|
+
return {
|
|
1612
|
+
toolMessage: {
|
|
1613
|
+
role: 'tool',
|
|
1614
|
+
tool_call_id: toolCallId,
|
|
1615
|
+
name: fallbackToolName,
|
|
1616
|
+
content: JSON.stringify({
|
|
1617
|
+
authoritative: true,
|
|
1618
|
+
escalatedFrom: toolName,
|
|
1619
|
+
result: cappedFallback,
|
|
1620
|
+
instruction: fallbackInstruction
|
|
1621
|
+
})
|
|
1622
|
+
},
|
|
1623
|
+
toolName: fallbackToolName,
|
|
1624
|
+
result: fallbackResult,
|
|
1625
|
+
escalatedFrom: toolName
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1386
1630
|
toolResultTracker.total++;
|
|
1387
1631
|
toolResultTracker.toolNames.push(toolName);
|
|
1388
1632
|
if (result.status === 'not_found') toolResultTracker.notFound++;
|
|
@@ -1392,7 +1636,7 @@ export class KikuAgent {
|
|
|
1392
1636
|
const cappedResult = this._capToolResultForHistory(result);
|
|
1393
1637
|
|
|
1394
1638
|
let instruction = result.status === 'not_found'
|
|
1395
|
-
? 'CRITICAL: No matching data was found for this query in the catalog.
|
|
1639
|
+
? 'CRITICAL: No matching data was found for this query in the verified catalog. If the user\'s inquiry concerns recent activities, unreleased works, live news, Weibo/social updates, or rumors, you SHOULD call external search tools (search_chinese_web, search_news, or web_search) to check for external evidence before concluding. If external searches have already been completed or are not applicable, state clearly in the user\'s language that the record was not found in the verified database. Do NOT fabricate facts, dates, or relationships.'
|
|
1396
1640
|
: result.status === 'error'
|
|
1397
1641
|
? 'CRITICAL: The tool failed to retrieve data. Do NOT claim that the requested facts were verified. You MUST acknowledge the error and either retry or inform the user that the information could not be retrieved.'
|
|
1398
1642
|
: 'Use ONLY the specific facts present in this result when answering. Do NOT add, infer, or extrapolate information beyond what is explicitly provided. Do NOT fabricate additional details, dates, names, or relationships not present in this result. Do not echo raw JSON data — summarize in natural language while preserving factual accuracy.';
|
|
@@ -1455,11 +1699,18 @@ export class KikuAgent {
|
|
|
1455
1699
|
promptForLLM
|
|
1456
1700
|
);
|
|
1457
1701
|
|
|
1458
|
-
const
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
? "
|
|
1462
|
-
:
|
|
1702
|
+
const inDomain = isQueryInDomain(promptForLLM);
|
|
1703
|
+
const langPrompt = inDomain
|
|
1704
|
+
? (dominantLang === 'zh'
|
|
1705
|
+
? "请根据上述工具查询结果回答,回答深度须与问题相称:单一事实类问题(日期、名字、数字、是/否)用 1-4 句话直接简洁作答,不加标题或表格;仅当问题是比较、排序、列表或深度分析时,才使用完整的 Markdown 结构(标题、要点、表格)并附上具体的 YouTube 真实链接(如 Direct Watch: https://www.youtube.com/watch?v=... 或 Search: https://www.youtube.com/results?search_query=...)。不要用无关段落填充简短的事实性回答,但也绝不能遗漏用户明确要求的任何条目。\n\n【反幻觉守则 — 必须遵守】只陈述工具结果中明确包含的事实。禁止编造、推测或补充工具结果中不存在的剧名、歌曲名、角色名、品牌名、日期或任何细节。如果工具结果不足以完整回答,请明确说明哪些部分未经验证,而不是凭空补全。"
|
|
1706
|
+
: dominantLang === 'en'
|
|
1707
|
+
? "Based on the tool results above, provide a response whose depth matches the question: for simple single-fact questions (a date, a name, a number, yes/no) answer concisely and directly in 1-4 sentences without headers or tables; only for comparison, ranking, list, or deep-dive questions use rich detail with well-organized Markdown headers, bullet points, and verified YouTube links (https://www.youtube.com/results?search_query=...). Never pad short factual answers with filler sections, and never omit any item the user explicitly requested.\n\n【Anti-Hallucination Mandate — MANDATORY】Only state facts explicitly present in the tool results above. Do NOT fabricate, infer, or supplement drama titles, song names, character roles, brand names, dates, or any details not found in the tool results. If the tool results are insufficient to fully answer, explicitly note which parts are unverified rather than inventing plausible-sounding details."
|
|
1708
|
+
: "สรุปคำตอบจากผลลัพธ์เครื่องมือข้างต้น โดยให้ความลึกของคำตอบสมดุลกับคำถาม: คำถามข้อเท็จจริงเดี่ยว (วันที่ ชื่อ ตัวเลข ใช่/ไม่ใช่) ตอบสั้น ตรงประเด็น 1-4 ประโยค โดยไม่ต้องมีหัวข้อหรือตาราง ส่วนคำถามเปรียบเทียบ จัดอันดับ จัดรายการ หรือวิเคราะห์เชิงลึก จึงจัดโครงสร้างด้วยหัวข้อ Markdown, ตาราง และ bullet points พร้อมแสดงลิงก์ YouTube จริง (Direct Watch Link และ https://www.youtube.com/results?search_query=...) อย่างครบถ้วน ห้ามเติมเนื้อหาฟุ่มเฟือยในคำตอบสั้น แต่ห้ามลดทอนรายการที่ผู้ใช้ระบุขอมาทุกข้อ\n\n【กฎป้องกันการแต่งข้อมูล — บังคับใช้】ระบุเฉพาะข้อเท็จจริงที่มีอยู่จริงในผลลัพธ์เครื่องมือเท่านั้น ห้ามสร้างชื่อละคร เพลง ตัวละคร แบรนด์ วันที่ หรือรายละเอียดใดๆ ที่ไม่มีอยู่ในผลลัพธ์เครื่องมือ หากข้อมูลไม่เพียงพอสำหรับคำตอบที่สมบูรณ์ ให้ระบุชัดเจนว่าส่วนใดยังไม่ได้รับการยืนยัน แทนการเติมข้อมูลที่ฟังดูน่าเชื่อแต่ไม่มีหลักฐาน")
|
|
1709
|
+
: (dominantLang === 'zh'
|
|
1710
|
+
? "请针对用户的通用或外部问题,提供清晰、准确、有条理且有帮助的回答。若有网络检索结果可作为参考,亦可自然运用通用知识进行解答。"
|
|
1711
|
+
: dominantLang === 'en'
|
|
1712
|
+
? "Please provide a clear, accurate, and well-structured answer to the user's general or open-domain question. Reference web search results if available, and feel free to use general knowledge."
|
|
1713
|
+
: "โปรดให้คำตอบที่ชัดเจน ถูกต้อง และมีประโยชน์ต่อคำถามทั่วไปหรือหัวข้อภายนอกนี้ โดยสามารถอ้างอิงจากผลการค้นหาเว็บ (หากมี) หรือตอบด้วยความรู้รอบตัวได้อย่างเป็นธรรมชาติ");
|
|
1463
1714
|
|
|
1464
1715
|
const synthHistoryBase = this.conversationHistory.length;
|
|
1465
1716
|
this.conversationHistory.push({ role: 'user', content: langPrompt });
|
|
@@ -1478,8 +1729,12 @@ export class KikuAgent {
|
|
|
1478
1729
|
...turnDirectives,
|
|
1479
1730
|
...this.conversationHistory.slice(1)
|
|
1480
1731
|
],
|
|
1481
|
-
temperature: 0.3,
|
|
1732
|
+
temperature: runTemperature ?? 0.3,
|
|
1733
|
+
topP: runTopP ?? null,
|
|
1734
|
+
minP: runMinP,
|
|
1735
|
+
repeatPenalty: runRepeatPenalty,
|
|
1482
1736
|
maxTokens: OUTPUT_TOKEN_BUDGET,
|
|
1737
|
+
contextLimit: runContextLimit,
|
|
1483
1738
|
stream: true,
|
|
1484
1739
|
signal,
|
|
1485
1740
|
onThought: (thoughtChunk) => {
|
|
@@ -1616,10 +1871,11 @@ export class KikuAgent {
|
|
|
1616
1871
|
_computeConfidenceScore(toolResultTracker) {
|
|
1617
1872
|
if (toolResultTracker.total === 0) return 0;
|
|
1618
1873
|
|
|
1619
|
-
const
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1622
|
-
const
|
|
1874
|
+
const total = toolResultTracker.total;
|
|
1875
|
+
const successRatio = toolResultTracker.success / total;
|
|
1876
|
+
const errorRatio = toolResultTracker.error / total;
|
|
1877
|
+
const notFoundRatio = toolResultTracker.notFound / total;
|
|
1878
|
+
const base = Math.max(0, successRatio - errorRatio * 0.5 - notFoundRatio * 0.35);
|
|
1623
1879
|
|
|
1624
1880
|
const hasVerifiedSource = toolResultTracker.success > 0;
|
|
1625
1881
|
const allFailed = toolResultTracker.success === 0 && (toolResultTracker.notFound > 0 || toolResultTracker.error > 0);
|
|
@@ -1631,6 +1887,23 @@ export class KikuAgent {
|
|
|
1631
1887
|
}
|
|
1632
1888
|
|
|
1633
1889
|
async _performSelfCritique(toolResultTracker, dominantLang, originalQuery) {
|
|
1890
|
+
const inDomain = isQueryInDomain(originalQuery);
|
|
1891
|
+
if (!inDomain) {
|
|
1892
|
+
const th = dominantLang === 'th';
|
|
1893
|
+
const zh = dominantLang === 'zh';
|
|
1894
|
+
const prefix = th
|
|
1895
|
+
? '【คำสั่งระบบสำหรับหัวข้อทั่วไป — เปิดกว้าง】'
|
|
1896
|
+
: zh
|
|
1897
|
+
? '【开放领域问答指令】'
|
|
1898
|
+
: '【OPEN-DOMAIN SYNTHESIS DIRECTIVE】';
|
|
1899
|
+
const body = th
|
|
1900
|
+
? 'คำถามนี้เป็นความรู้ทั่วไปหรือหัวข้อภายนอกที่ไม่เกี่ยวกับผลงานของศิลปินโดยตรง คุณสามารถตอบได้อย่างเป็นธรรมชาติ มีประโยชน์ และถูกต้องตามความรู้รอบตัว หรืออ้างอิงจากผลการค้นหาเว็บภายนอก (หากมี) โดยไม่ต้องบังคับหาข้อมูลในแค็ตตาล็อกของศิลปิน'
|
|
1901
|
+
: zh
|
|
1902
|
+
? '此问题属于通用知识或外部话题。您可以结合常识与外部网页搜索结果自然、准确、有建设性地回答,无需强行关联艺人数据库。'
|
|
1903
|
+
: 'This query relates to open-domain knowledge or general topics. Provide a helpful, accurate, and natural answer using your general knowledge and web search results without forcing catalog references.';
|
|
1904
|
+
return `${prefix}\n${body}\nOriginal query: ${originalQuery}`;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1634
1907
|
const confidence = this._computeConfidenceScore(toolResultTracker);
|
|
1635
1908
|
|
|
1636
1909
|
const th = dominantLang === 'th';
|
package/server/agent/appPaths.js
CHANGED
|
@@ -24,3 +24,34 @@ export const SETTINGS_FILE = path.join(KIKU_DATA_DIR, 'settings.json');
|
|
|
24
24
|
export const PROFILES_FILE = path.join(KIKU_DATA_DIR, 'profiles.json');
|
|
25
25
|
export const HIERARCHICAL_MEMORY_DIR = path.join(KIKU_DATA_DIR, 'memory_nodes');
|
|
26
26
|
export const ARTIFACTS_STORE_DIR = path.join(KIKU_DATA_DIR, 'artifacts_store');
|
|
27
|
+
|
|
28
|
+
export function getSystemDrive(env = process.env) {
|
|
29
|
+
return env.SystemDrive || 'C:';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getProgramFilesDir(env = process.env) {
|
|
33
|
+
return env.ProgramFiles || env.ProgramW6432 || path.join(getSystemDrive(env), 'Program Files');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getProgramFilesX86Dir(env = process.env) {
|
|
37
|
+
return env['ProgramFiles(x86)'] || path.join(getSystemDrive(env), 'Program Files (x86)');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getLocalAppDataDir(env = process.env) {
|
|
41
|
+
return env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getAppDataDir(env = process.env) {
|
|
45
|
+
return env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function resolveDynamicWindowsAppPaths(...relativeParts) {
|
|
49
|
+
const dirs = [
|
|
50
|
+
getProgramFilesDir(),
|
|
51
|
+
getProgramFilesX86Dir(),
|
|
52
|
+
getLocalAppDataDir(),
|
|
53
|
+
path.join(getLocalAppDataDir(), 'Programs'),
|
|
54
|
+
getAppDataDir(),
|
|
55
|
+
];
|
|
56
|
+
return [...new Set(dirs.map(d => path.join(d, ...relativeParts)))];
|
|
57
|
+
}
|