kiku-agent 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +7 -7
  2. package/package.json +4 -7
  3. package/server/agent/agentCore.js +2 -2
  4. package/server/agent/catalogEntityResolver.js +8 -0
  5. package/server/agent/cli.js +4 -0
  6. package/server/agent/eval/AGENTS.md +228 -0
  7. package/server/agent/eval/analyze.py +684 -0
  8. package/server/agent/eval/gates.json +15 -0
  9. package/server/agent/eval/modules/analysis/compare.js +198 -0
  10. package/server/agent/eval/modules/analysis/gates.js +72 -0
  11. package/server/agent/eval/modules/analysis/judge.js +70 -0
  12. package/server/agent/eval/modules/core/cli.js +453 -0
  13. package/server/agent/eval/modules/core/config.js +60 -0
  14. package/server/agent/eval/modules/core/store.js +236 -0
  15. package/server/agent/eval/modules/evaluation/cases.js +689 -0
  16. package/server/agent/eval/modules/evaluation/runner.js +298 -0
  17. package/server/agent/eval/modules/evaluation/scoring.js +351 -0
  18. package/server/agent/eval/modules/evaluation/worker.js +122 -0
  19. package/server/agent/eval/modules/reporting/benchmark.js +265 -0
  20. package/server/agent/eval/modules/reporting/benchmarkPng.js +487 -0
  21. package/server/agent/eval/modules/reporting/dashboard.js +1406 -0
  22. package/server/agent/eval/modules/server/evalApi.js +1099 -0
  23. package/server/agent/eval/modules/ui/evalUi.js +4796 -0
  24. package/server/agent/eval/modules/utils/smokes.js +119 -0
  25. package/server/agent/ink/App.jsx +348 -0
  26. package/server/agent/ink/Panel.jsx +54 -0
  27. package/server/agent/ink/PromptInput.jsx +321 -0
  28. package/server/agent/ink/TaskPlanPanel.jsx +88 -0
  29. package/server/agent/ink/ThinkingPanel.jsx +68 -0
  30. package/server/agent/ink/ToolResult.jsx +133 -0
  31. package/server/agent/ink/main.jsx +195 -0
  32. package/server/agent/ink/useEventBus.js +218 -0
  33. package/server/agent/memory/contextAllocator.js +214 -0
  34. package/server/agent/memory/hierarchicalStore.js +523 -0
  35. package/server/agent/memory/reflectionWorker.js +110 -0
  36. package/server/agent/prompts.js +1 -1
  37. package/server/agent/telemetry/hardwareTiers.js +332 -0
  38. package/server/agent/telemetry/runtimeWatchdog.js +66 -0
  39. package/server/agent/telemetry/techPowerUpClient.js +682 -0
  40. package/server/agent/telemetry/techpowerup-mcp.json +22 -0
  41. package/server/agent/tests/agentBubbleSystem.test.js +65 -0
  42. package/server/agent/tests/agentFollowUps.test.js +127 -0
  43. package/server/agent/tests/apiRouter.test.js +108 -0
  44. package/server/agent/tests/architectureFixes.test.js +81 -0
  45. package/server/agent/tests/architectureRefactoring.test.js +194 -0
  46. package/server/agent/tests/autoResearch.test.js +64 -0
  47. package/server/agent/tests/bilibiliEmbed.test.js +251 -0
  48. package/server/agent/tests/catalogSync.test.js +130 -0
  49. package/server/agent/tests/citations.test.js +180 -0
  50. package/server/agent/tests/clarificationAnalytics.test.js +219 -0
  51. package/server/agent/tests/clarifyingQuestions.test.js +594 -0
  52. package/server/agent/tests/cliAutomation.test.js +121 -0
  53. package/server/agent/tests/cloudProviders.test.js +234 -0
  54. package/server/agent/tests/commandInput.test.js +24 -0
  55. package/server/agent/tests/commands.test.js +417 -0
  56. package/server/agent/tests/contextIntelligence.test.js +162 -0
  57. package/server/agent/tests/conversationSafety.test.js +53 -0
  58. package/server/agent/tests/decisionAndSearchEnhancements.test.js +135 -0
  59. package/server/agent/tests/dramaAnswerQuality.test.js +73 -0
  60. package/server/agent/tests/dynamicCatalogIngestion.test.js +285 -0
  61. package/server/agent/tests/dynamicRoutingAndSearch.test.js +92 -0
  62. package/server/agent/tests/edgeCasesScenarios.test.js +49 -0
  63. package/server/agent/tests/entertainmentMetrics.test.js +126 -0
  64. package/server/agent/tests/envBootstrap.test.js +87 -0
  65. package/server/agent/tests/envCommand.test.js +215 -0
  66. package/server/agent/tests/errorHandling.test.js +80 -0
  67. package/server/agent/tests/errors.test.js +13 -0
  68. package/server/agent/tests/evalAnalyze.test.js +54 -0
  69. package/server/agent/tests/evalCommand.test.js +54 -0
  70. package/server/agent/tests/evalCorpus.test.js +126 -0
  71. package/server/agent/tests/evalHarness.test.js +62 -0
  72. package/server/agent/tests/evalJudgeContext.test.js +38 -0
  73. package/server/agent/tests/evalMetrics.test.js +312 -0
  74. package/server/agent/tests/evalStore.test.js +190 -0
  75. package/server/agent/tests/evalStudio.test.js +179 -0
  76. package/server/agent/tests/feedbackLearning.test.js +186 -0
  77. package/server/agent/tests/firstRun.test.js +44 -0
  78. package/server/agent/tests/gemma4eOptimization.test.js +95 -0
  79. package/server/agent/tests/hardwareTiers.test.js +206 -0
  80. package/server/agent/tests/hybridWebSearch.test.js +192 -0
  81. package/server/agent/tests/judgeService.test.js +251 -0
  82. package/server/agent/tests/lanDiscovery.test.js +319 -0
  83. package/server/agent/tests/mcpClient.test.js +201 -0
  84. package/server/agent/tests/modelManager.test.js +109 -0
  85. package/server/agent/tests/multilingualScenarios.test.js +69 -0
  86. package/server/agent/tests/newCommands.test.js +347 -0
  87. package/server/agent/tests/newCommandsTui.test.js +141 -0
  88. package/server/agent/tests/newTools.test.js +113 -0
  89. package/server/agent/tests/newsIntelligence.test.js +178 -0
  90. package/server/agent/tests/nextGenArchitecture.test.js +99 -0
  91. package/server/agent/tests/offlineInput.test.js +217 -0
  92. package/server/agent/tests/packagingGuard.test.js +57 -0
  93. package/server/agent/tests/presentation.test.js +61 -0
  94. package/server/agent/tests/providerPersistence.test.js +39 -0
  95. package/server/agent/tests/queryBenchmarks.test.js +83 -0
  96. package/server/agent/tests/queryDetails.test.js +126 -0
  97. package/server/agent/tests/realWorldValidation.test.js +391 -0
  98. package/server/agent/tests/resilienceAndConcurrency.test.js +117 -0
  99. package/server/agent/tests/runtimeWatchdog.test.js +32 -0
  100. package/server/agent/tests/sanitizer.test.js +37 -0
  101. package/server/agent/tests/scenariosData.js +378 -0
  102. package/server/agent/tests/schemaRouting.test.js +54 -0
  103. package/server/agent/tests/securityAuditRemediation.test.js +214 -0
  104. package/server/agent/tests/securityHardening.test.js +146 -0
  105. package/server/agent/tests/securitySanitizer.test.js +38 -0
  106. package/server/agent/tests/sessionAndCopy.test.js +232 -0
  107. package/server/agent/tests/sidebarControls.test.js +101 -0
  108. package/server/agent/tests/statefulMemory.test.js +270 -0
  109. package/server/agent/tests/subagent.test.js +216 -0
  110. package/server/agent/tests/subagentProgress.test.js +109 -0
  111. package/server/agent/tests/subagentTextFallback.test.js +115 -0
  112. package/server/agent/tests/suggestions.test.js +199 -0
  113. package/server/agent/tests/suggestionsTui.test.js +251 -0
  114. package/server/agent/tests/telemetryAndProfiles.test.js +179 -0
  115. package/server/agent/tests/terminalImage.test.js +80 -0
  116. package/server/agent/tests/terminalMarkdown.test.js +166 -0
  117. package/server/agent/tests/terminalText.test.js +133 -0
  118. package/server/agent/tests/textProtocolLoop.test.js +126 -0
  119. package/server/agent/tests/textToolParsing.test.js +139 -0
  120. package/server/agent/tests/theme.test.js +26 -0
  121. package/server/agent/tests/toolRegistryParity.test.js +53 -0
  122. package/server/agent/tests/toolRoutingRegressions.test.js +119 -0
  123. package/server/agent/tests/tools.test.js +259 -0
  124. package/server/agent/tests/unifiedEndpoints.test.js +152 -0
  125. package/server/agent/tests/v110Features.test.js +262 -0
  126. package/server/agent/tests/versionBump.test.js +69 -0
  127. package/server/agent/tests/vramEstimator.test.js +520 -0
  128. package/server/agent/tests/webChatInspection.test.js +300 -0
  129. package/server/agent/tests/webChatMemory.test.js +112 -0
  130. package/server/agent/tests/webChatSecurity.test.js +169 -0
  131. package/server/agent/tests/webExtract.test.js +261 -0
  132. package/server/agent/tests/webSources.test.js +247 -0
  133. package/server/agent/websearch/adapters/duckduckgo.js +97 -0
  134. package/server/agent/websearch/adapters/jina.js +77 -0
  135. package/server/agent/websearch/adapters/searxng.js +57 -0
  136. package/server/agent/websearch/core/canonical.js +89 -0
  137. package/server/agent/websearch/core/fusion.js +81 -0
  138. package/server/agent/websearch/core/types.js +29 -0
  139. package/server/agent/websearch/extract.js +605 -0
  140. package/server/agent/websearch/index.js +43 -0
  141. package/server/agent/websearch/orchestrator.js +266 -0
  142. package/server/agent/websearch/resilience/breaker.js +97 -0
  143. package/server/agent/websearch/resilience/cache.js +59 -0
  144. package/server/agent/websearch/resilience/limiter.js +93 -0
  145. package/server/agent/websearch/security/filter.js +36 -0
  146. package/server/agent/websearch/security/ssrf.js +289 -0
  147. package/server/agent/websearch/telemetry.js +71 -0
  148. package/server/apiRouter.js +7 -11
  149. package/server/eval/judgeRubrics.js +110 -0
  150. package/server/eval/judgeService.js +290 -0
  151. package/server/eval/runBenchmark.js +182 -0
  152. package/server/mcp/examples/librechat.example.yaml +16 -0
  153. package/server/mcp/tests/connection.test.js +156 -0
  154. package/server/routes/agent.js +55 -0
  155. package/server/supabase_schema.sql +63 -0
@@ -0,0 +1,77 @@
1
+ import { createSearchResult } from '../core/types.js';
2
+ import { safeFetchWithPinning } from '../security/ssrf.js';
3
+
4
+
5
+ export async function searchJina(query, options = {}) {
6
+ const maxResults = Number(options.limit) || 10;
7
+ const timeoutMs = Number(options.timeoutMs) || 10000;
8
+ const results = [];
9
+ const seenLinks = new Set();
10
+
11
+ try {
12
+ const searchUrl = `https://s.jina.ai/${encodeURIComponent(query)}`;
13
+ const res = await safeFetchWithPinning(searchUrl, {
14
+ headers: {
15
+ 'Accept': 'application/json, text/plain, */*',
16
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
17
+ 'X-No-Cache': 'false'
18
+ },
19
+ timeoutMs,
20
+ signal: options.signal
21
+ });
22
+
23
+ if (!res.ok) {
24
+ return [];
25
+ }
26
+
27
+ const contentType = res.headers.get('content-type') || '';
28
+ if (contentType.includes('application/json')) {
29
+ const json = await res.json();
30
+ const items = Array.isArray(json?.data) ? json.data : (Array.isArray(json?.results) ? json.results : []);
31
+
32
+ for (const item of items.slice(0, maxResults)) {
33
+ const link = item?.url || item?.link;
34
+ if (link && !seenLinks.has(link)) {
35
+ seenLinks.add(link);
36
+ results.push(createSearchResult({
37
+ link,
38
+ title: item.title || query,
39
+ snippet: item.description || item.content || '',
40
+ engine: 'jina',
41
+ score: 1.0 - (results.length * 0.05),
42
+ metadata: {
43
+ publishedTime: item.publishedTime || null
44
+ }
45
+ }));
46
+ }
47
+ }
48
+ } else {
49
+
50
+ const text = await res.text();
51
+
52
+ const blockRegex = /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)([\s\S]*?)(?=\n\[|$)/g;
53
+ let match;
54
+ while ((match = blockRegex.exec(text)) !== null && results.length < maxResults) {
55
+ const title = match[1].trim();
56
+ const link = match[2].trim();
57
+ const snippet = match[3].replace(/\s+/g, ' ').trim().slice(0, 300);
58
+
59
+ if (link && !seenLinks.has(link)) {
60
+ seenLinks.add(link);
61
+ results.push(createSearchResult({
62
+ link,
63
+ title,
64
+ snippet,
65
+ engine: 'jina',
66
+ score: 1.0 - (results.length * 0.05)
67
+ }));
68
+ }
69
+ }
70
+ }
71
+ } catch {
72
+
73
+ return [];
74
+ }
75
+
76
+ return results;
77
+ }
@@ -0,0 +1,57 @@
1
+ import { createSearchResult } from '../core/types.js';
2
+ import { safeFetchWithPinning } from '../security/ssrf.js';
3
+
4
+
5
+ export async function searchSearXNG(query, options = {}) {
6
+ const baseUrl = options.baseUrl || process.env.SEARXNG_URL;
7
+ if (!baseUrl) {
8
+
9
+ return [];
10
+ }
11
+
12
+ const maxResults = Number(options.limit) || 10;
13
+ const timeoutMs = Number(options.timeoutMs) || 8000;
14
+ const results = [];
15
+
16
+ try {
17
+ const cleanBase = baseUrl.replace(/\/+$/, '');
18
+ const searchUrl = `${cleanBase}/search?q=${encodeURIComponent(query)}&format=json&language=${options.language || 'auto'}`;
19
+
20
+ const res = await safeFetchWithPinning(searchUrl, {
21
+ headers: {
22
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
23
+ 'Accept': 'application/json, text/plain, */*'
24
+ },
25
+ timeoutMs,
26
+ signal: options.signal
27
+ });
28
+
29
+ if (!res.ok) {
30
+ return [];
31
+ }
32
+
33
+ const json = await res.json();
34
+ const rawResults = Array.isArray(json?.results) ? json.results : [];
35
+
36
+ for (const item of rawResults.slice(0, maxResults)) {
37
+ if (item?.url && item?.title) {
38
+ results.push(createSearchResult({
39
+ link: item.url,
40
+ title: item.title,
41
+ snippet: item.content || item.snippet || '',
42
+ engine: 'searxng',
43
+ score: Number(item.score) || (1.0 - results.length * 0.05),
44
+ metadata: {
45
+ engines: item.engines || [],
46
+ category: item.category || 'general'
47
+ }
48
+ }));
49
+ }
50
+ }
51
+ } catch {
52
+
53
+ return [];
54
+ }
55
+
56
+ return results;
57
+ }
@@ -0,0 +1,89 @@
1
+ const TRACKING_PARAMS = new Set([
2
+ 'utm_source',
3
+ 'utm_medium',
4
+ 'utm_campaign',
5
+ 'utm_term',
6
+ 'utm_content',
7
+ 'utm_id',
8
+ 'fbclid',
9
+ 'gclid',
10
+ 'dclid',
11
+ 'gclsrc',
12
+ 'ref',
13
+ 'ref_src',
14
+ 'spm',
15
+ 'spm_id_from',
16
+ 'from',
17
+ 'source',
18
+ '_ga',
19
+ '_gl',
20
+ 'mc_eid',
21
+ 'yclid',
22
+ 'trk',
23
+ 'wt_mc',
24
+ 'ocid'
25
+ ]);
26
+
27
+
28
+ export function canonicalizeUrl(rawUrl) {
29
+ if (!rawUrl || typeof rawUrl !== 'string') return '';
30
+ const trimmed = rawUrl.trim();
31
+
32
+ let parsed;
33
+ try {
34
+ parsed = new URL(trimmed);
35
+ } catch {
36
+ return trimmed;
37
+ }
38
+
39
+
40
+ if (parsed.protocol === 'http:' && !parsed.hostname.includes('localhost') && !parsed.hostname.startsWith('127.')) {
41
+ parsed.protocol = 'https:';
42
+ }
43
+
44
+
45
+ let hostname = parsed.hostname.toLowerCase();
46
+ if (hostname.startsWith('www.')) {
47
+ hostname = hostname.slice(4);
48
+ }
49
+ parsed.hostname = hostname;
50
+
51
+
52
+ if ((parsed.protocol === 'https:' && parsed.port === '443') || (parsed.protocol === 'http:' && parsed.port === '80')) {
53
+ parsed.port = '';
54
+ }
55
+
56
+
57
+ if (parsed.pathname.length > 1 && parsed.pathname.endsWith('/')) {
58
+ parsed.pathname = parsed.pathname.slice(0, -1);
59
+ }
60
+
61
+
62
+ const searchParams = new URLSearchParams(parsed.search);
63
+ const remainingKeys = [];
64
+ for (const [key] of searchParams.entries()) {
65
+ const lowerKey = key.toLowerCase();
66
+ if (TRACKING_PARAMS.has(lowerKey) || lowerKey.startsWith('utm_')) {
67
+ searchParams.delete(key);
68
+ } else {
69
+ if (!remainingKeys.includes(key)) remainingKeys.push(key);
70
+ }
71
+ }
72
+
73
+ remainingKeys.sort();
74
+ const sortedParams = new URLSearchParams();
75
+ for (const key of remainingKeys) {
76
+ const vals = searchParams.getAll(key);
77
+ for (const val of vals) {
78
+ sortedParams.append(key, val);
79
+ }
80
+ }
81
+
82
+ const sortedQueryString = sortedParams.toString();
83
+ parsed.search = sortedQueryString ? `?${sortedQueryString}` : '';
84
+
85
+
86
+ parsed.hash = '';
87
+
88
+ return parsed.href;
89
+ }
@@ -0,0 +1,81 @@
1
+ import { canonicalizeUrl } from './canonical.js';
2
+
3
+ export const DEFAULT_RRF_K = 60;
4
+
5
+ /**
6
+ * Merges and ranks search results across multiple engines using Reciprocal Rank Fusion (RRF).
7
+ * Formula: Score(d) = Sum_{e in E} ( 1 / (k + rank_e(d)) )
8
+ *
9
+ * @param {Array<Array<import('./types.js').SearchResult>>} engineResultLists - Array of result arrays from engines
10
+ * @param {Object} [options]
11
+ * @param {number} [options.k=60] - Smoothing constant
12
+ * @param {number} [options.limit=10] - Max fused results to return
13
+ * @returns {Array<import('./types.js').SearchResult>} Fused, deduplicated and ranked results
14
+ */
15
+ export function fuseSearchResults(engineResultLists = [], options = {}) {
16
+ const k = Number.isFinite(options.k) ? Math.max(1, options.k) : DEFAULT_RRF_K;
17
+ const limit = Number.isFinite(options.limit) ? Math.max(1, options.limit) : 10;
18
+
19
+
20
+ const aggregated = new Map();
21
+
22
+ for (const list of engineResultLists) {
23
+ if (!Array.isArray(list)) continue;
24
+
25
+ for (let i = 0; i < list.length; i++) {
26
+ const item = list[i];
27
+ if (!item || !item.link) continue;
28
+
29
+ const canonicalLink = canonicalizeUrl(item.link);
30
+ if (!canonicalLink) continue;
31
+
32
+ const rank = i + 1;
33
+ const rrfContribution = 1 / (k + rank);
34
+
35
+ let existing = aggregated.get(canonicalLink);
36
+ if (!existing) {
37
+ existing = {
38
+ link: canonicalLink,
39
+ title: item.title || '',
40
+ snippet: item.snippet || '',
41
+ engine: item.engine || 'meta',
42
+ score: 0,
43
+ metadata: {
44
+ engines: [item.engine].filter(Boolean),
45
+ ranks: { [item.engine]: rank },
46
+ originalLinks: [item.link],
47
+ snippets: item.snippet ? [item.snippet] : []
48
+ }
49
+ };
50
+ aggregated.set(canonicalLink, existing);
51
+ } else {
52
+ if (item.engine && !existing.metadata.engines.includes(item.engine)) {
53
+ existing.metadata.engines.push(item.engine);
54
+ }
55
+ if (item.engine) {
56
+ existing.metadata.ranks[item.engine] = rank;
57
+ }
58
+ if (item.link && !existing.metadata.originalLinks.includes(item.link)) {
59
+ existing.metadata.originalLinks.push(item.link);
60
+ }
61
+ if (item.title && (!existing.title || item.title.length > existing.title.length)) {
62
+ existing.title = item.title;
63
+ }
64
+ if (item.snippet && !existing.metadata.snippets.includes(item.snippet)) {
65
+ existing.metadata.snippets.push(item.snippet);
66
+
67
+ if (item.snippet.length > existing.snippet.length) {
68
+ existing.snippet = item.snippet;
69
+ }
70
+ }
71
+ }
72
+
73
+ existing.score += rrfContribution;
74
+ }
75
+ }
76
+
77
+ const results = Array.from(aggregated.values());
78
+ results.sort((a, b) => b.score - a.score);
79
+
80
+ return results.slice(0, limit);
81
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Canonical Search Result Data Contract
3
+ *
4
+ * @typedef {Object} SearchResult
5
+ * @property {string} link - Canonical destination URL
6
+ * @property {string} title - Sanitized result title
7
+ * @property {string} snippet - Extracted text snippet or abstract
8
+ * @property {'duckduckgo' | 'searxng' | 'jina' | 'openserp' | 'yacy' | string} engine - Origin search engine
9
+ * @property {number} [score] - Optional relevance / RRF score
10
+ * @property {Record<string, unknown>} [metadata] - Optional engine-specific metadata
11
+ */
12
+
13
+ export function createSearchResult({
14
+ link,
15
+ title = '',
16
+ snippet = '',
17
+ engine = 'duckduckgo',
18
+ score = 0,
19
+ metadata = {}
20
+ }) {
21
+ return {
22
+ link: String(link || '').trim(),
23
+ title: String(title || '').trim(),
24
+ snippet: String(snippet || '').trim(),
25
+ engine: String(engine || 'duckduckgo').toLowerCase(),
26
+ score: Number.isFinite(Number(score)) ? Number(score) : 0,
27
+ metadata: metadata && typeof metadata === 'object' ? metadata : {}
28
+ };
29
+ }