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.
Files changed (232) hide show
  1. package/README.md +69 -12
  2. package/package.json +5 -12
  3. package/server/agent/agentCore.js +319 -46
  4. package/server/agent/appPaths.js +31 -0
  5. package/server/agent/audioPlayer.js +339 -12
  6. package/server/agent/autoContext.js +193 -0
  7. package/server/agent/catalogEntityResolver.js +170 -28
  8. package/server/agent/clarifyingQuestions.js +137 -35
  9. package/server/agent/cli.js +177 -48
  10. package/server/agent/cloudAdapters.js +116 -0
  11. package/server/agent/commandRegistry.js +409 -80
  12. package/server/agent/commands.js +1056 -125
  13. package/server/agent/config.js +1088 -690
  14. package/server/agent/contextCompactor.js +213 -21
  15. package/server/agent/cpuMetrics.js +199 -0
  16. package/server/agent/engineService.js +591 -0
  17. package/server/agent/eval/AGENTS.md +228 -0
  18. package/server/agent/eval/analyze.py +684 -0
  19. package/server/agent/eval/gates.json +15 -0
  20. package/server/agent/eval/modules/analysis/compare.js +198 -0
  21. package/server/agent/eval/modules/analysis/gates.js +72 -0
  22. package/server/agent/eval/modules/analysis/judge.js +70 -0
  23. package/server/agent/eval/modules/core/cli.js +453 -0
  24. package/server/agent/eval/modules/core/config.js +60 -0
  25. package/server/agent/eval/modules/core/store.js +236 -0
  26. package/server/agent/eval/modules/evaluation/cases.js +689 -0
  27. package/server/agent/eval/modules/evaluation/runner.js +288 -0
  28. package/server/agent/eval/modules/evaluation/scoring.js +363 -0
  29. package/server/agent/eval/modules/evaluation/worker.js +122 -0
  30. package/server/agent/eval/modules/reporting/benchmark.js +265 -0
  31. package/server/agent/eval/modules/reporting/benchmarkPng.js +487 -0
  32. package/server/agent/eval/modules/reporting/dashboard.js +1406 -0
  33. package/server/agent/eval/modules/server/evalApi.js +1099 -0
  34. package/server/agent/eval/modules/ui/evalUi.js +4799 -0
  35. package/server/agent/eval/modules/utils/smokes.js +119 -0
  36. package/server/agent/eventBus.js +1 -0
  37. package/server/agent/ink/main.jsx +196 -191
  38. package/server/agent/jobManager.js +11 -1
  39. package/server/agent/lanDiscovery.js +721 -23
  40. package/server/agent/llmClient.js +317 -71
  41. package/server/agent/lmStudioWakeup.js +517 -65
  42. package/server/agent/locationService.js +797 -0
  43. package/server/agent/mcpQuizData.js +509 -0
  44. package/server/agent/memory/contextAllocator.js +19 -7
  45. package/server/agent/memory.js +3 -1
  46. package/server/agent/modelCompatibility.js +352 -0
  47. package/server/agent/modelDefaults.js +1 -0
  48. package/server/agent/modelManager.js +46 -2
  49. package/server/agent/newsWatch.js +9 -3
  50. package/server/agent/processManager.js +229 -0
  51. package/server/agent/prompts.js +174 -8
  52. package/server/agent/routingInterceptor.js +9 -1
  53. package/server/agent/sanitizer.js +41 -6
  54. package/server/agent/searchQueryPlanner.js +202 -0
  55. package/server/agent/session.js +59 -4
  56. package/server/agent/tests/agentBubbleSystem.test.js +65 -0
  57. package/server/agent/tests/agentFollowUps.test.js +253 -0
  58. package/server/agent/tests/agentMusicControl.test.js +245 -0
  59. package/server/agent/tests/apiRouter.test.js +108 -0
  60. package/server/agent/tests/architectureFixes.test.js +81 -0
  61. package/server/agent/tests/architectureRefactoring.test.js +194 -0
  62. package/server/agent/tests/autoContext.test.js +176 -0
  63. package/server/agent/tests/autoResearch.test.js +64 -0
  64. package/server/agent/tests/bilibiliEmbed.test.js +296 -0
  65. package/server/agent/tests/catalogSync.test.js +130 -0
  66. package/server/agent/tests/chatHardening.test.js +121 -0
  67. package/server/agent/tests/chineseWebSearchEscalation.test.js +62 -0
  68. package/server/agent/tests/citations.test.js +180 -0
  69. package/server/agent/tests/clarificationAnalytics.test.js +219 -0
  70. package/server/agent/tests/clarifyingQuestions.test.js +627 -0
  71. package/server/agent/tests/cliAutomation.test.js +158 -0
  72. package/server/agent/tests/cloudProviders.test.js +322 -0
  73. package/server/agent/tests/commandInput.test.js +24 -0
  74. package/server/agent/tests/commands.test.js +506 -0
  75. package/server/agent/tests/contextIntelligence.test.js +209 -0
  76. package/server/agent/tests/conversationSafety.test.js +53 -0
  77. package/server/agent/tests/cpuMetrics.test.js +101 -0
  78. package/server/agent/tests/decisionAndSearchEnhancements.test.js +167 -0
  79. package/server/agent/tests/dramaAnswerQuality.test.js +73 -0
  80. package/server/agent/tests/dynamicCatalogIngestion.test.js +285 -0
  81. package/server/agent/tests/dynamicRoutingAndSearch.test.js +92 -0
  82. package/server/agent/tests/edgeCasesScenarios.test.js +131 -0
  83. package/server/agent/tests/engineService.test.js +436 -0
  84. package/server/agent/tests/engineUnload.test.js +94 -0
  85. package/server/agent/tests/entertainmentMetrics.test.js +126 -0
  86. package/server/agent/tests/envBootstrap.test.js +87 -0
  87. package/server/agent/tests/envCommand.test.js +284 -0
  88. package/server/agent/tests/errorHandling.test.js +80 -0
  89. package/server/agent/tests/errors.test.js +13 -0
  90. package/server/agent/tests/evalAnalyze.test.js +54 -0
  91. package/server/agent/tests/evalCommand.test.js +54 -0
  92. package/server/agent/tests/evalCorpus.test.js +126 -0
  93. package/server/agent/tests/evalHarness.test.js +62 -0
  94. package/server/agent/tests/evalJudgeContext.test.js +38 -0
  95. package/server/agent/tests/evalMetrics.test.js +320 -0
  96. package/server/agent/tests/evalStore.test.js +190 -0
  97. package/server/agent/tests/evalStudio.test.js +179 -0
  98. package/server/agent/tests/feedbackLearning.test.js +186 -0
  99. package/server/agent/tests/fetchApi.test.js +99 -0
  100. package/server/agent/tests/firstRun.test.js +44 -0
  101. package/server/agent/tests/gemma4eOptimization.test.js +95 -0
  102. package/server/agent/tests/hardwareTiers.test.js +206 -0
  103. package/server/agent/tests/hybridWebSearch.test.js +194 -0
  104. package/server/agent/tests/judgeService.test.js +251 -0
  105. package/server/agent/tests/lanDiscovery.test.js +324 -0
  106. package/server/agent/tests/lanInterfaces.test.js +510 -0
  107. package/server/agent/tests/lmStudioWakeup.test.js +278 -0
  108. package/server/agent/tests/locationTool.test.js +278 -0
  109. package/server/agent/tests/mcpClient.test.js +201 -0
  110. package/server/agent/tests/memoryRoute.test.js +173 -0
  111. package/server/agent/tests/memoryUiNormalization.test.js +75 -0
  112. package/server/agent/tests/modelCompatibility.test.js +148 -0
  113. package/server/agent/tests/modelManager.test.js +141 -0
  114. package/server/agent/tests/multilingualScenarios.test.js +69 -0
  115. package/server/agent/tests/musicControlUiBridge.test.js +113 -0
  116. package/server/agent/tests/newCommands.test.js +347 -0
  117. package/server/agent/tests/newCommandsTui.test.js +141 -0
  118. package/server/agent/tests/newTools.test.js +113 -0
  119. package/server/agent/tests/newsIntelligence.test.js +178 -0
  120. package/server/agent/tests/nextGenArchitecture.test.js +101 -0
  121. package/server/agent/tests/offlineInput.test.js +217 -0
  122. package/server/agent/tests/openDomainPrompt.test.js +197 -0
  123. package/server/agent/tests/openDomainSearch.test.js +121 -0
  124. package/server/agent/tests/packagingGuard.test.js +57 -0
  125. package/server/agent/tests/presentation.test.js +61 -0
  126. package/server/agent/tests/processManager.test.js +144 -0
  127. package/server/agent/tests/providerPersistence.test.js +44 -0
  128. package/server/agent/tests/queryBenchmarks.test.js +83 -0
  129. package/server/agent/tests/queryDetails.test.js +126 -0
  130. package/server/agent/tests/quickActionsAndModals.test.js +180 -0
  131. package/server/agent/tests/realWorldValidation.test.js +391 -0
  132. package/server/agent/tests/resilienceAndConcurrency.test.js +117 -0
  133. package/server/agent/tests/runtimeWatchdog.test.js +32 -0
  134. package/server/agent/tests/sanitizer.test.js +37 -0
  135. package/server/agent/tests/scenariosData.js +378 -0
  136. package/server/agent/tests/schemaRouting.test.js +54 -0
  137. package/server/agent/tests/searchQueryPlanner.test.js +108 -0
  138. package/server/agent/tests/securityAuditRemediation.test.js +221 -0
  139. package/server/agent/tests/securityAuditRemediations2.test.js +154 -0
  140. package/server/agent/tests/securityHardening.test.js +146 -0
  141. package/server/agent/tests/securitySanitizer.test.js +38 -0
  142. package/server/agent/tests/sessionAndCopy.test.js +267 -0
  143. package/server/agent/tests/sidebarControls.test.js +135 -0
  144. package/server/agent/tests/statefulMemory.test.js +277 -0
  145. package/server/agent/tests/subagent.test.js +216 -0
  146. package/server/agent/tests/subagentProgress.test.js +109 -0
  147. package/server/agent/tests/subagentTextFallback.test.js +115 -0
  148. package/server/agent/tests/suggestions.test.js +199 -0
  149. package/server/agent/tests/suggestionsTui.test.js +251 -0
  150. package/server/agent/tests/telemetryAndProfiles.test.js +179 -0
  151. package/server/agent/tests/terminalImage.test.js +80 -0
  152. package/server/agent/tests/terminalMarkdown.test.js +166 -0
  153. package/server/agent/tests/terminalText.test.js +133 -0
  154. package/server/agent/tests/textProtocolLoop.test.js +197 -0
  155. package/server/agent/tests/textToolParsing.test.js +187 -0
  156. package/server/agent/tests/theme.test.js +26 -0
  157. package/server/agent/tests/toolRegistryParity.test.js +53 -0
  158. package/server/agent/tests/toolRoutingRegressions.test.js +160 -0
  159. package/server/agent/tests/tools.test.js +259 -0
  160. package/server/agent/tests/unifiedEndpoints.test.js +159 -0
  161. package/server/agent/tests/v110Features.test.js +262 -0
  162. package/server/agent/tests/versionBump.test.js +69 -0
  163. package/server/agent/tests/vramEstimator.test.js +595 -0
  164. package/server/agent/tests/webChatDocs.test.js +199 -0
  165. package/server/agent/tests/webChatInferenceControl.test.js +298 -0
  166. package/server/agent/tests/webChatInspection.test.js +551 -0
  167. package/server/agent/tests/webChatMcp.test.js +94 -0
  168. package/server/agent/tests/webChatMemory.test.js +112 -0
  169. package/server/agent/tests/webChatSecurity.test.js +169 -0
  170. package/server/agent/tests/webExtract.test.js +284 -0
  171. package/server/agent/tests/webSources.test.js +281 -0
  172. package/server/agent/textToolProtocol.js +173 -46
  173. package/server/agent/toolRouter.js +318 -44
  174. package/server/agent/tools.js +877 -96
  175. package/server/agent/ui.js +39 -34
  176. package/server/agent/vramService.js +35 -54
  177. package/server/agent/webSearch.js +441 -162
  178. package/server/agent/websearch/orchestrator.js +15 -5
  179. package/server/agent/websearch/resilience/cache.js +9 -2
  180. package/server/agent/websearch/security/ssrf.js +41 -10
  181. package/server/agent/youtubeAuth.js +5 -20
  182. package/server/apiRouter.js +5558 -4422
  183. package/server/eval/judgeRubrics.js +110 -0
  184. package/server/eval/judgeService.js +290 -0
  185. package/server/eval/runBenchmark.js +182 -0
  186. package/server/mcp/data/discography.js +2 -2
  187. package/server/mcp/examples/antigravity.example.json +17 -0
  188. package/server/mcp/examples/librechat.example.yaml +16 -0
  189. package/server/mcp/handler.js +8 -4
  190. package/server/mcp/security.js +220 -21
  191. package/server/mcp/server.js +2 -1
  192. package/server/mcp/tests/connection.test.js +162 -0
  193. package/server/mcp/tests/mcpKeyAuth.test.js +156 -0
  194. package/server/mcp/tools.js +7 -1
  195. package/server/supabase_migration_prefix.sql +102 -0
  196. package/server/supabase_schema.sql +63 -0
  197. package/server/web-chat/core/connection.js +179 -218
  198. package/server/web-chat/core/conversationContext.js +9 -2
  199. package/server/web-chat/core/directCatalogEngine.js +52 -28
  200. package/server/web-chat/core/dramaKnowledge.js +33 -22
  201. package/server/web-chat/core/followUpEngine.js +735 -81
  202. package/server/web-chat/core/futureEventGuard.js +5 -1
  203. package/server/web-chat/core/musicControlAction.js +70 -0
  204. package/server/web-chat/core/security.js +32 -21
  205. package/server/web-chat/core/toolInspector.js +6 -6
  206. package/server/web-chat/core/urlGuard.js +45 -0
  207. package/server/web-chat/router.js +204 -157
  208. package/server/web-chat/routes/chatRoute.js +885 -488
  209. package/server/web-chat/routes/engineRoute.js +270 -0
  210. package/server/web-chat/routes/exportRoute.js +1 -1
  211. package/server/web-chat/routes/lanDiscoveryRoute.js +17 -2
  212. package/server/web-chat/routes/lmStudioLoadRoute.js +172 -0
  213. package/server/web-chat/routes/mcpRoute.js +386 -0
  214. package/server/web-chat/routes/memoryRoute.js +253 -0
  215. package/server/web-chat/routes/providerRoute.js +49 -16
  216. package/server/web-chat/routes/staticRoute.js +306 -17
  217. package/server/web-chat/routes/statusRoute.js +194 -73
  218. package/server/web-chat/routes/suggestRoute.js +11 -3
  219. package/server/web-chat/routes/verifyRoute.js +26 -4
  220. package/server/web-chat/server.js +7 -6
  221. package/server/web-chat/ui/docsBuilder.js +3558 -0
  222. package/server/web-chat/ui/htmlBuilder.js +12 -0
  223. package/server/web-chat/ui/scripts/client.js +3401 -1302
  224. package/server/web-chat/ui/scripts/webchatI18n.js +155 -153
  225. package/server/web-chat/ui/settingsBuilder.js +7870 -0
  226. package/server/web-chat/ui/styles/lan-card.css +165 -0
  227. package/server/web-chat/ui/styles/main.css +4289 -447
  228. package/server/web-chat/ui/sw.js +64 -0
  229. package/server/web-chat/ui/templates/body.html +407 -281
  230. package/src/data/awardsData.js +146 -146
  231. package/src/data/musicVideoData.js +6 -4
  232. package/src/lib/vram/estimator.js +195 -19
@@ -1,73 +1,194 @@
1
- import { toolsSchema } from '../../agent/tools.js';
2
- import { resolveAgentConnection, currentAgent } from '../core/connection.js';
3
- import { config, CLOUD_PROVIDERS, getProviderBaseUrl, getUnifiedProviderCatalog } from '../../agent/config.js';
4
- import { getAgentMemorySnapshot } from '../core/memorySnapshot.js';
5
- import { sendJson, sendError } from '../core/errorHandler.js';
6
- import { extractApiKey } from '../core/security.js';
7
-
8
- export async function handleStatusRoute(req, res, urlObj, port) {
9
- try {
10
- const queryProvider = urlObj.searchParams.get('provider');
11
- const queryModel = urlObj.searchParams.get('model');
12
- const queryApiKey = extractApiKey(req);
13
- const querySessionId = urlObj.searchParams.get('sessionId');
14
- const queryBaseUrl = urlObj.searchParams.get('baseUrl');
15
-
16
- const conn = await resolveAgentConnection({
17
- provider: queryProvider,
18
- model: queryModel,
19
- apiKey: queryApiKey,
20
- sessionId: querySessionId,
21
- baseUrl: queryBaseUrl || undefined,
22
- });
23
-
24
- const totalTools = conn.agent?.getAllToolsSchema?.().length || toolsSchema.length;
25
- const serverDefaultProvider = currentAgent?.client?.provider || config.activeProvider || 'lmstudio';
26
- const serverDefaultModel = currentAgent?.client?.model || config.providers?.[serverDefaultProvider]?.model || 'google/gemma-4-e4b';
27
- const serverDefaultProviderName = currentAgent?.client?.providerName || (CLOUD_PROVIDERS?.[serverDefaultProvider]?.name) || serverDefaultProvider;
28
- const serverDefaultBaseUrl = currentAgent?.client?.baseUrl || getProviderBaseUrl(serverDefaultProvider);
29
- let localEndpoints = null;
30
- let providerCatalog = null;
31
- try {
32
- const catalog = getUnifiedProviderCatalog();
33
- localEndpoints = catalog.localEndpoints;
34
- providerCatalog = catalog.providers;
35
- } catch {}
36
-
37
- sendJson(res, 200, {
38
- status: 'ok',
39
- server: 'Kiku Web Chatbot',
40
- port,
41
- connected: conn.ready,
42
- state: conn.ready ? 'ready' : (conn.state || 'server_offline'),
43
- provider: conn.provider,
44
- model: conn.model,
45
- activeModel: conn.model,
46
- activeLoadedModel: conn.resolution?.activeLoadedModel || conn.model,
47
- loadedModels: conn.models || [],
48
- usedFallback: conn.usedFallback || false,
49
- serverDefaultProvider,
50
- serverDefaultModel,
51
- serverDefaultProviderName,
52
- serverDefaultBaseUrl,
53
- localEndpoints,
54
- providers: providerCatalog,
55
- hasServerAgent: Boolean(currentAgent),
56
- error: conn.error || null,
57
- capabilities: {
58
- reactAgent: Boolean(conn.agent),
59
- streaming: true,
60
- toolCalling: Boolean(conn.agent),
61
- localTools: toolsSchema.length,
62
- mcpTools: Math.max(0, totalTools - toolsSchema.length),
63
- totalTools,
64
- sessionMemory: Boolean(conn.agent),
65
- longTermMemory: Boolean(conn.agent?.memory),
66
- cachedAgent: conn.cached === true,
67
- },
68
- memory: getAgentMemorySnapshot(conn.agent, querySessionId)
69
- });
70
- } catch (err) {
71
- sendError(res, 500, err.message);
72
- }
73
- }
1
+ import { credentialFingerprint } from '../core/connection.js';
2
+ import { toolsSchema } from '../../agent/tools.js';
3
+ import { resolveAgentConnection, currentAgent } from '../core/connection.js';
4
+ import { config, CLOUD_PROVIDERS, getProviderBaseUrl, getUnifiedProviderCatalog, getPersistedInferenceSettings, getProvider } from '../../agent/config.js';
5
+ import { getAgentMemorySnapshot } from '../core/memorySnapshot.js';
6
+ import { sendJson, sendError } from '../core/errorHandler.js';
7
+ import { extractApiKey, isWebChatAdmin } from '../core/security.js';
8
+ import { validateInferenceBaseUrl, isTrustedRequest, sanitizeInferenceError } from '../core/urlGuard.js';
9
+
10
+ // Full /api/status builds an agent and probes the upstream server; dedupe
11
+ // bursts (chat-page poll + settings page) behind a tiny TTL cache.
12
+ const FULL_STATUS_CACHE_TTL_MS = 3_000;
13
+ let fullStatusCache = { key: null, at: 0, payload: null };
14
+
15
+ function fullStatusCacheKey({ provider, model, baseUrl, apiKey }) {
16
+ return [provider || 'auto', model || 'auto', baseUrl || '-', credentialFingerprint(apiKey)].join('|');
17
+ }
18
+
19
+ export async function handleStatusRoute(req, res, urlObj, port) {
20
+ try {
21
+ const queryProvider = urlObj.searchParams.get('provider');
22
+ const queryModel = urlObj.searchParams.get('model');
23
+ const queryApiKey = extractApiKey(req);
24
+ const querySessionId = urlObj.searchParams.get('sessionId');
25
+ const queryBaseUrl = urlObj.searchParams.get('baseUrl');
26
+ const light = urlObj.searchParams.get('light') === '1';
27
+
28
+ if (queryProvider && queryProvider !== 'auto' && !getProvider(queryProvider)) return sendError(res, 400, 'Unknown provider');
29
+ if (queryBaseUrl) {
30
+ const guard = await validateInferenceBaseUrl(queryBaseUrl, { trusted: isTrustedRequest(req) });
31
+ if (!guard.ok) {
32
+ return sendError(res, 400, `Invalid baseUrl: ${guard.reason}`);
33
+ }
34
+ }
35
+
36
+ if (light) {
37
+ return sendJson(res, 200, await buildLightStatus({ port, provider: queryProvider, model: queryModel, baseUrl: queryBaseUrl }));
38
+ }
39
+
40
+ const cacheKey = String(isTrustedRequest(req)) + '|' + querySessionId + '|' + fullStatusCacheKey({ provider: queryProvider, model: queryModel, baseUrl: queryBaseUrl, apiKey: queryApiKey });
41
+ const now = Date.now();
42
+ if (fullStatusCache.key === cacheKey && now - fullStatusCache.at < FULL_STATUS_CACHE_TTL_MS) {
43
+ return sendJson(res, 200, { ...fullStatusCache.payload, cached: true });
44
+ }
45
+
46
+ const conn = await resolveAgentConnection({
47
+ provider: queryProvider,
48
+ model: queryModel,
49
+ apiKey: isWebChatAdmin(req) ? undefined : queryApiKey,
50
+ callerIsTrusted: isTrustedRequest(req),
51
+ sessionId: querySessionId,
52
+ baseUrl: queryBaseUrl || undefined,
53
+ // Auto-starting LM Studio from a status GET is a side effect; only trusted
54
+ // (loopback/admin) callers may wake the local engine this way.
55
+ allowAutoStart: isTrustedRequest(req),
56
+ });
57
+
58
+ const payload = await buildFullStatus({ conn, queryProvider, queryModel, queryApiKey, querySessionId, port });
59
+ payload.error = payload.error ? sanitizeInferenceError(payload.error, isTrustedRequest(req)) : null;
60
+ fullStatusCache = { key: cacheKey, at: Date.now(), payload };
61
+ sendJson(res, 200, payload);
62
+ } catch (err) {
63
+ sendError(res, err.statusCode || 502, sanitizeInferenceError(err, isTrustedRequest(req)));
64
+ }
65
+ }
66
+
67
+ async function buildLightStatus({ port, provider, model, baseUrl }) {
68
+ const serverProvider = currentAgent?.client?.provider || config.activeProvider || 'lmstudio';
69
+ const activeBaseUrl = (typeof baseUrl === 'string' && baseUrl.trim())
70
+ ? baseUrl.trim().replace(/\/+$/, '')
71
+ : (currentAgent?.client?.baseUrl || getProviderBaseUrl(provider || serverProvider));
72
+
73
+ const connected = Boolean(currentAgent?.client && currentAgent.client.provider === (provider && provider !== 'auto' ? provider : serverProvider) && (!baseUrl || currentAgent.client.baseUrl === baseUrl));
74
+ let localEndpoints = null;
75
+ let providerCatalog = null;
76
+ try {
77
+ const catalog = getUnifiedProviderCatalog();
78
+ localEndpoints = catalog.localEndpoints;
79
+ providerCatalog = catalog.providers;
80
+ } catch {}
81
+
82
+ const serverDefaultModel = currentAgent?.client?.model || config.providers?.[serverProvider]?.model || 'google/gemma-4-e4b';
83
+ return {
84
+ status: 'ok',
85
+ server: 'Kiku Web Chatbot',
86
+ port,
87
+ light: true,
88
+ connected,
89
+ state: connected ? 'unprobed' : 'unknown',
90
+ healthVerified: false,
91
+ provider: serverProvider,
92
+ model: serverDefaultModel,
93
+ activeModel: serverDefaultModel,
94
+ loadedModels: [],
95
+ usedFallback: false,
96
+ serverDefaultProvider: serverProvider,
97
+ serverDefaultModel,
98
+ serverDefaultProviderName: currentAgent?.client?.providerName || CLOUD_PROVIDERS?.[serverProvider]?.name || serverProvider,
99
+ serverDefaultBaseUrl: currentAgent?.client?.baseUrl || getProviderBaseUrl(serverProvider),
100
+ contextLimit: getPersistedInferenceSettings().contextLimit,
101
+ inference: getPersistedInferenceSettings(),
102
+ localEndpoints,
103
+ providers: providerCatalog,
104
+ hasServerAgent: Boolean(currentAgent),
105
+ error: null,
106
+ capabilities: {
107
+ reactAgent: Boolean(currentAgent),
108
+ streaming: true,
109
+ toolCalling: Boolean(currentAgent),
110
+ localTools: toolsSchema.length,
111
+ mcpTools: 0,
112
+ totalTools: toolsSchema.length,
113
+ sessionMemory: Boolean(currentAgent),
114
+ longTermMemory: Boolean(currentAgent?.memory),
115
+ cachedAgent: false,
116
+ light: true,
117
+ },
118
+ mcp: {
119
+ endpoint: '/mcp',
120
+ protocolVersion: '2025-11-25',
121
+ transport: 'streamable-http',
122
+ online: true,
123
+ },
124
+ memory: null,
125
+ };
126
+ }
127
+
128
+ async function buildFullStatus({ conn, queryProvider, queryModel, queryApiKey, querySessionId, port }) {
129
+ const totalTools = conn.agent?.getAllToolsSchema?.().length || toolsSchema.length;
130
+ const serverDefaultProvider = currentAgent?.client?.provider || config.activeProvider || 'lmstudio';
131
+ const serverDefaultModel = currentAgent?.client?.model || config.providers?.[serverDefaultProvider]?.model || 'google/gemma-4-e4b';
132
+ const serverDefaultProviderName = currentAgent?.client?.providerName || (CLOUD_PROVIDERS?.[serverDefaultProvider]?.name) || serverDefaultProvider;
133
+ const serverDefaultBaseUrl = currentAgent?.client?.baseUrl || getProviderBaseUrl(serverDefaultProvider);
134
+ let localEndpoints = null;
135
+ let providerCatalog = null;
136
+ try {
137
+ const catalog = getUnifiedProviderCatalog();
138
+ localEndpoints = catalog.localEndpoints;
139
+ providerCatalog = catalog.providers;
140
+ } catch {}
141
+
142
+ const isLocal = conn.provider === 'lmstudio' || conn.provider === 'vllm';
143
+ const rawActive = conn.resolution?.activeLoadedModel || null;
144
+ const isModelLoaded = isLocal ? Boolean(rawActive) : Boolean(conn.ready);
145
+ const activeLoadedModel = rawActive || (!isLocal ? conn.model : null);
146
+ const loadedModels = conn.resolution?.loadedModels || (rawActive ? [rawActive] : (!isLocal ? conn.models || [] : []));
147
+ const effectiveState = !isModelLoaded && isLocal ? 'server_online_model_not_loaded' : (conn.ready ? 'ready' : (conn.state || 'server_offline'));
148
+
149
+ return {
150
+ status: 'ok',
151
+ server: 'Kiku Web Chatbot',
152
+ port,
153
+ light: false,
154
+ connected: conn.ready,
155
+ isModelLoaded,
156
+ state: effectiveState,
157
+ provider: conn.provider,
158
+ model: conn.model,
159
+ activeModel: conn.model,
160
+ activeLoadedModel,
161
+ loadedModels,
162
+ usedFallback: conn.usedFallback || false,
163
+ serverDefaultProvider,
164
+ serverDefaultModel,
165
+ serverDefaultProviderName,
166
+ serverDefaultBaseUrl,
167
+ // Effective engine context-budget (CLI KIKU_CONTEXT_LIMIT env; 0 = unset).
168
+ // The /settings Context Window slider syncs against this value.
169
+ contextLimit: getPersistedInferenceSettings().contextLimit,
170
+ inference: getPersistedInferenceSettings(),
171
+ localEndpoints,
172
+ providers: providerCatalog,
173
+ hasServerAgent: Boolean(currentAgent),
174
+ error: conn.error || null,
175
+ capabilities: {
176
+ reactAgent: Boolean(conn.agent),
177
+ streaming: true,
178
+ toolCalling: Boolean(conn.agent),
179
+ localTools: toolsSchema.length,
180
+ mcpTools: Math.max(0, totalTools - toolsSchema.length),
181
+ totalTools,
182
+ sessionMemory: Boolean(conn.agent),
183
+ longTermMemory: Boolean(conn.agent?.memory),
184
+ cachedAgent: conn.cached === true,
185
+ },
186
+ mcp: {
187
+ endpoint: '/mcp',
188
+ protocolVersion: '2025-11-25',
189
+ transport: 'streamable-http',
190
+ online: true,
191
+ },
192
+ memory: null
193
+ };
194
+ }
@@ -1,8 +1,10 @@
1
1
  import { executeTool } from '../../agent/tools.js';
2
2
  import { CATEGORIZED_SUGGESTIONS, DEFAULT_SUGGESTIONS } from '../ui/scripts/suggestionsData.js';
3
- import { resolveAgentConnection } from '../core/connection.js';
3
+ import { config, getProvider } from '../../agent/config.js';
4
+ import { isTrustedRequest } from '../core/urlGuard.js';
5
+ import { resolveAgentConnection, currentAgent } from '../core/connection.js';
4
6
  import { parseJsonBody, sendJson, sendError } from '../core/errorHandler.js';
5
- import { extractApiKey } from '../core/security.js';
7
+ import { extractApiKey, isWebChatAdmin } from '../core/security.js';
6
8
 
7
9
  export async function handleSuggestionsRoute(req, res) {
8
10
  sendJson(res, 200, {
@@ -30,6 +32,9 @@ export async function handleAiSuggestRoute(req, res) {
30
32
  body = await parseJsonBody(req);
31
33
  } catch {}
32
34
 
35
+ const provider = (!body.provider || body.provider === 'auto') ? (currentAgent?.client?.provider || config.activeProvider) : body.provider;
36
+ if (!getProvider(provider)) return sendError(res, 400, 'Unknown provider');
37
+ if (!['lmstudio', 'vllm', 'custom'].includes(provider) && !isTrustedRequest(req)) return sendError(res, 403, 'Cloud inference requires local or admin access');
33
38
  const { topic = '' } = body;
34
39
  const limit = Math.min(Math.max(Number(body.limit) || 5, 2), 8);
35
40
  const lang = AI_SUGGEST_LANGS.has(String(body.lang || '').toLowerCase())
@@ -43,7 +48,10 @@ export async function handleAiSuggestRoute(req, res) {
43
48
  const conn = await resolveAgentConnection({
44
49
  provider: body.provider,
45
50
  model: body.model,
46
- apiKey,
51
+ apiKey: isWebChatAdmin(req) ? undefined : apiKey,
52
+ baseUrl: body.baseUrl,
53
+ callerIsTrusted: isTrustedRequest(req),
54
+ allowAutoStart: isTrustedRequest(req),
47
55
  sessionId: body.sessionId,
48
56
  });
49
57
  const controller = new AbortController();
@@ -1,5 +1,6 @@
1
1
  import { executeTool } from '../../agent/tools.js';
2
2
  import { parseJsonBody, sendJson, sendError } from '../core/errorHandler.js';
3
+ import { extractWordTokens, buildTermFrequencyVector, computeCosineSimilarity } from '../../agent/memory/contextAllocator.js';
3
4
 
4
5
  export async function handleVerifyRoute(req, res) {
5
6
  let body;
@@ -23,10 +24,31 @@ export async function handleVerifyRoute(req, res) {
23
24
  ? rawResults
24
25
  : Object.values(rawResults || {}).flat().filter(item => typeof item === 'object');
25
26
 
26
- const hasDirectMatch = flatItems.some(r =>
27
- String(r.title || r.name || '').toLowerCase().includes(claim.toLowerCase()) ||
28
- String(r.description || r.synopsis || '').toLowerCase().includes(claim.toLowerCase())
29
- );
27
+ const claimLower = claim.toLowerCase().trim();
28
+ const claimTokens = extractWordTokens(claim);
29
+ const claimVec = buildTermFrequencyVector(claimTokens);
30
+
31
+ let bestScore = 0;
32
+ for (const r of flatItems) {
33
+ const title = String(r.title || r.name || r.titleTh || r.titleCn || '').toLowerCase();
34
+ if (title && (claimLower.includes(title) || title.includes(claimLower))) {
35
+ bestScore = Math.max(bestScore, 0.8);
36
+ }
37
+ const itemText = [
38
+ r.title || r.name || '',
39
+ r.titleCn || '',
40
+ r.titleTh || '',
41
+ r.role || '',
42
+ r.year || '',
43
+ r.description || r.synopsis || ''
44
+ ].join(' ');
45
+ const itemTokens = extractWordTokens(itemText);
46
+ const itemVec = buildTermFrequencyVector(itemTokens);
47
+ const sim = computeCosineSimilarity(claimVec, itemVec);
48
+ if (sim > bestScore) bestScore = sim;
49
+ }
50
+
51
+ const hasDirectMatch = bestScore >= 0.25;
30
52
 
31
53
  result = {
32
54
  verdict: hasDirectMatch ? 'PARTIALLY_VERIFIED' : 'UNVERIFIED',
@@ -1,7 +1,9 @@
1
+ import '../agent/envBootstrap.js';
1
2
  import http from 'node:http';
2
3
  import { handleWebChatRequest } from './router.js';
3
- import { currentAgent, setCurrentAgent, webAgentCache } from './core/connection.js';
4
+ import { currentAgent, setCurrentAgent } from './core/connection.js';
4
5
  import { config } from '../agent/config.js';
6
+ import { KIKU_DEFAULT_MODEL } from '../agent/modelDefaults.js';
5
7
 
6
8
  let activeServer = null;
7
9
  let activePort = Number(process.env.PORT_WEB_CHAT || 3002);
@@ -25,7 +27,7 @@ export function getWebChatServerStatus() {
25
27
  port: activePort,
26
28
  url: formatServerUrl(activeHost, activePort),
27
29
  provider: currentAgent?.client?.provider || config.activeProvider || 'lmstudio',
28
- model: currentAgent?.client?.model || 'google/gemma-4-e4b',
30
+ model: currentAgent?.client?.model || KIKU_DEFAULT_MODEL,
29
31
  };
30
32
  }
31
33
 
@@ -36,10 +38,9 @@ export function stopWebChatServer() {
36
38
  try { activeServer.closeAllConnections(); } catch {}
37
39
  }
38
40
  activeServer.close(async () => {
39
- await Promise.allSettled(
40
- Array.from(webAgentCache.values(), connection => connection.agent?.saveSession?.())
41
- );
42
- webAgentCache.clear();
41
+ if (currentAgent?.saveSession) {
42
+ try { await currentAgent.saveSession(); } catch {}
43
+ }
43
44
  activeServer = null;
44
45
  resolve(true);
45
46
  });