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
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { REPO_ROOT, DEFAULTS } from '../core/config.js';
|
|
5
|
+
import { estimateTextTokens } from '../../../contextCompactor.js';
|
|
6
|
+
|
|
7
|
+
export async function runWebSmoke({ out = DEFAULTS.webSmokeOut, timeoutMs = 60000 } = {}) {
|
|
8
|
+
const outPath = path.isAbsolute(out) ? out : path.resolve(REPO_ROOT, out);
|
|
9
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
10
|
+
process.env.KIKU_DATA_DIR = await fs.mkdtemp(path.join(os.tmpdir(), 'kiku-web-eval-'));
|
|
11
|
+
const { executeTool } = await import('../../../tools.js');
|
|
12
|
+
const checks = [
|
|
13
|
+
['web_search', { query: 'Ju Jingyi Legend of Yunxi' }],
|
|
14
|
+
['search_chinese_web', { query: '鞠婧祎 芸汐传' }],
|
|
15
|
+
['fetch_webpage', { url: 'https://example.com' }],
|
|
16
|
+
['web_extract', { query: 'Ju Jingyi Legend of Yunxi', maxResults: 2 }],
|
|
17
|
+
];
|
|
18
|
+
const rows = [];
|
|
19
|
+
try {
|
|
20
|
+
for (const [tool, parameters] of checks) {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
let row;
|
|
23
|
+
try {
|
|
24
|
+
const result = await executeTool(tool, parameters, { signal: AbortSignal.timeout(timeoutMs) });
|
|
25
|
+
row = { tool, parameters, result, durationMs: Math.round(performance.now() - start) };
|
|
26
|
+
} catch (error) {
|
|
27
|
+
row = { tool, parameters, error: error.message, durationMs: Math.round(performance.now() - start) };
|
|
28
|
+
}
|
|
29
|
+
rows.push(row);
|
|
30
|
+
await fs.writeFile(outPath, JSON.stringify({ checkedAt: new Date().toISOString(), scope: 'Real external tool availability, not answer-quality scoring. Success status does not establish result relevance.', rows }, null, 2));
|
|
31
|
+
console.log(`${tool}: ${row.result?.status || row.error}; ${row.durationMs}ms`);
|
|
32
|
+
}
|
|
33
|
+
} finally {
|
|
34
|
+
await fs.rm(process.env.KIKU_DATA_DIR, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
return { out: outPath, rows };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function runResearchSmoke({ out = DEFAULTS.researchSmokeOut, model = DEFAULTS.model, baseUrl = DEFAULTS.baseUrl, timeoutMs = 180000 } = {}) {
|
|
40
|
+
const outPath = path.isAbsolute(out) ? out : path.resolve(REPO_ROOT, out);
|
|
41
|
+
const fsSync = await import('node:fs');
|
|
42
|
+
const dir = fsSync.mkdtempSync(path.join(os.tmpdir(), 'kiku-research-eval-'));
|
|
43
|
+
process.env.KIKU_DATA_DIR = dir;
|
|
44
|
+
const [{ LLMClient }, { ResearchOrchestrator }, { scoreResearchComplexity, shouldAutoResearch }] = await Promise.all([
|
|
45
|
+
import('../../../llmClient.js'), import('../../../research.js'), import('../../../agentCore.js'),
|
|
46
|
+
]);
|
|
47
|
+
const question = 'Compare In Blossom and Sword and Fairy 4 using the Kiku catalog and public sources. Verify the release years, the characters played by Ju Jingyi, and episode counts. Explain any source disagreement, and clearly distinguish unverified information. Provide a concise evidence report with sources.';
|
|
48
|
+
const client = new LLMClient({ provider: 'lmstudio', model, apiKey: 'lm-studio', baseUrl });
|
|
49
|
+
const started = Date.now();
|
|
50
|
+
const report = {
|
|
51
|
+
startedAt: new Date().toISOString(), model: client.model, question, timeoutMs,
|
|
52
|
+
complexity: scoreResearchComplexity(question), autoEligible: shouldAutoResearch(question, { mode: 'auto' }),
|
|
53
|
+
scope: 'Direct real ResearchOrchestrator run, default 3 workers and 3 iterations. Auto eligibility is checked separately; this does not test the main agent decision to invoke research.',
|
|
54
|
+
state: 'running', maxConcurrentRequests: 0, requests: [], progress: [],
|
|
55
|
+
};
|
|
56
|
+
fsSync.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
57
|
+
const save = () => { report.elapsedMs = Date.now() - started; fsSync.writeFileSync(outPath, JSON.stringify(report, null, 2)); };
|
|
58
|
+
let active = 0;
|
|
59
|
+
const chat = client.chat.bind(client);
|
|
60
|
+
client.chat = async options => {
|
|
61
|
+
const row = { startedMs: Date.now() - started };
|
|
62
|
+
report.requests.push(row);
|
|
63
|
+
report.maxConcurrentRequests = Math.max(report.maxConcurrentRequests, ++active);
|
|
64
|
+
save();
|
|
65
|
+
try { const result = await chat(options); row.usage = result?.usage; return result; }
|
|
66
|
+
catch (error) { row.error = error.message; throw error; }
|
|
67
|
+
finally { active--; row.endedMs = Date.now() - started; save(); }
|
|
68
|
+
};
|
|
69
|
+
const research = new ResearchOrchestrator({ client });
|
|
70
|
+
const hardStop = setTimeout(() => {
|
|
71
|
+
report.state = 'timeout'; report.error = 'Hard timeout after cancellation grace period'; save(); process.exit(1);
|
|
72
|
+
}, timeoutMs + 15000);
|
|
73
|
+
try {
|
|
74
|
+
report.result = await research.run(question, {
|
|
75
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
76
|
+
onProgress: event => { report.progress.push({ elapsedMs: Date.now() - started, ...event }); save(); console.log(JSON.stringify(event)); },
|
|
77
|
+
});
|
|
78
|
+
report.state = 'completed';
|
|
79
|
+
} catch (error) {
|
|
80
|
+
report.state = 'error'; report.error = error.message; process.exitCode = 1;
|
|
81
|
+
} finally {
|
|
82
|
+
clearTimeout(hardStop); research.cancel(); save(); fsSync.rmSync(dir, { recursive: true, force: true });
|
|
83
|
+
}
|
|
84
|
+
console.log(JSON.stringify({ state: report.state, elapsedMs: report.elapsedMs, requests: report.requests.length, maxConcurrentRequests: report.maxConcurrentRequests }));
|
|
85
|
+
return report;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function runTokenCalibration({ out = DEFAULTS.tokenCalibrationOut, model = DEFAULTS.model, baseUrl = DEFAULTS.baseUrl } = {}) {
|
|
89
|
+
const outPath = path.isAbsolute(out) ? out : path.resolve(REPO_ROOT, out);
|
|
90
|
+
const samples = {
|
|
91
|
+
th: 'จวีจิ้งอีเป็นนักร้องและนักแสดงชาวจีน แฟนคลับต้องการตรวจสอบข้อมูลผลงานจากแหล่งอ้างอิง หากไม่มีข้อมูลเพียงพอควรบอกตรงไปตรงมาและไม่แต่งรายละเอียดเพิ่มเติม ',
|
|
92
|
+
en: 'The assistant should verify the title, character and release year against the catalog. If evidence is missing, explain the uncertainty instead of inventing details. ',
|
|
93
|
+
zh: '请根据资料库核实电视剧名称、角色和发行年份。如果没有足够证据,请明确说明不确定性,不要编造细节。',
|
|
94
|
+
mixed: 'ข้อมูล作品 In Blossom (花间令) ปี 2024: {"role":"Yang Caiwei","episodes":32,"verified":true}. ',
|
|
95
|
+
};
|
|
96
|
+
const rows = [];
|
|
97
|
+
for (const [language, sample] of Object.entries(samples)) {
|
|
98
|
+
const measurements = [];
|
|
99
|
+
for (const repeats of [3, 6]) {
|
|
100
|
+
const content = sample.repeat(repeats).trim();
|
|
101
|
+
const started = Date.now();
|
|
102
|
+
const response = await fetch(`${baseUrl.replace(/\/$/, '')}/chat/completions`, {
|
|
103
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' }, signal: AbortSignal.timeout(90000),
|
|
104
|
+
body: JSON.stringify({ model, messages: [{ role: 'user', content }], max_tokens: 1, temperature: 0, stream: false }),
|
|
105
|
+
});
|
|
106
|
+
if (!response.ok) throw new Error(`Calibration HTTP ${response.status}`);
|
|
107
|
+
const result = await response.json();
|
|
108
|
+
if (!Number.isFinite(result.usage?.prompt_tokens)) throw new Error('Provider did not report prompt token usage');
|
|
109
|
+
measurements.push({ repeats, characters: content.length, estimate: estimateTextTokens(content), promptTokens: result.usage.prompt_tokens, durationMs: Date.now() - started });
|
|
110
|
+
}
|
|
111
|
+
const estimatedDelta = measurements[1].estimate - measurements[0].estimate;
|
|
112
|
+
const measuredDelta = measurements[1].promptTokens - measurements[0].promptTokens;
|
|
113
|
+
rows.push({ language, sample, measurements, estimatedDelta, measuredDelta, ratio: measuredDelta > 0 ? estimatedDelta / measuredDelta : null });
|
|
114
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
115
|
+
await fs.writeFile(outPath, JSON.stringify({ model, checkedAt: new Date().toISOString(), method: 'Real prompt usage delta between 3 and 6 repeats; chat-template overhead cancels. Four samples only, no universal tokenizer bound or o200k claim.', rows }, null, 2));
|
|
116
|
+
console.log(`${language}: estimated delta ${estimatedDelta}, measured ${measuredDelta}, ratio ${rows.at(-1).ratio}`);
|
|
117
|
+
}
|
|
118
|
+
return { out: outPath, rows };
|
|
119
|
+
}
|
package/server/agent/eventBus.js
CHANGED
|
@@ -83,6 +83,7 @@ export const Events = Object.freeze({
|
|
|
83
83
|
AGENT_TOOL_START: 'agent:tool:start',
|
|
84
84
|
AGENT_TOOL_RESULT: 'agent:tool:result',
|
|
85
85
|
AGENT_TOOL_ERROR: 'agent:tool:error',
|
|
86
|
+
AGENT_TOOL_ESCALATED:'agent:tool:escalated',
|
|
86
87
|
|
|
87
88
|
AGENT_PLAN_START: 'agent:plan:start',
|
|
88
89
|
AGENT_PLAN_STEP_UPDATE: 'agent:plan:step:update',
|
|
@@ -2,194 +2,199 @@ import React from 'react';
|
|
|
2
2
|
import { render } from 'ink';
|
|
3
3
|
import '../youtubeAuth.js';
|
|
4
4
|
import { App } from './App.jsx';
|
|
5
|
-
import { KikuAgent } from '../agentCore.js';
|
|
6
|
-
import { LMStudioClient } from '../llmClient.js';
|
|
7
|
-
import { toolsSchema } from '../tools.js';
|
|
8
|
-
import { config } from '../config.js';
|
|
9
|
-
import { COMMAND_DEFINITIONS } from '../commandRegistry.js';
|
|
10
|
-
import { C, UI_ICONS } from '../ui.js';
|
|
11
|
-
import { existsSync } from 'node:fs';
|
|
12
|
-
import { spawn } from 'node:child_process';
|
|
13
|
-
import { PACKAGE_VERSION } from '../version.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else if (arg === '--
|
|
35
|
-
else if (arg === '--
|
|
36
|
-
else if (arg === '--
|
|
37
|
-
else if (arg === '--
|
|
38
|
-
else if (arg === '--
|
|
39
|
-
else if (arg === '--
|
|
40
|
-
else if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
]
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
5
|
+
import { KikuAgent } from '../agentCore.js';
|
|
6
|
+
import { LMStudioClient } from '../llmClient.js';
|
|
7
|
+
import { toolsSchema } from '../tools.js';
|
|
8
|
+
import { config } from '../config.js';
|
|
9
|
+
import { COMMAND_DEFINITIONS } from '../commandRegistry.js';
|
|
10
|
+
import { C, UI_ICONS } from '../ui.js';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { spawn } from 'node:child_process';
|
|
13
|
+
import { PACKAGE_VERSION } from '../version.js';
|
|
14
|
+
import { resolveDynamicWindowsAppPaths } from '../appPaths.js';
|
|
15
|
+
import { registerBackgroundProcess } from '../processManager.js';
|
|
16
|
+
|
|
17
|
+
function parseCliArgs() {
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const options = {
|
|
20
|
+
query: null,
|
|
21
|
+
model: 'google/gemma-4-e4b',
|
|
22
|
+
url: null,
|
|
23
|
+
showTools: false,
|
|
24
|
+
showStats: false,
|
|
25
|
+
thinking: 'show',
|
|
26
|
+
verbose: false,
|
|
27
|
+
help: false,
|
|
28
|
+
version: false
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
const arg = args[i];
|
|
33
|
+
if (arg === '--help' || arg === '-h') options.help = true;
|
|
34
|
+
else if (arg === '--version' || arg === '-V') options.version = true;
|
|
35
|
+
else if (arg === '--tools' || arg === '-t') options.showTools = true;
|
|
36
|
+
else if (arg === '--stats' || arg === '-s') options.showStats = true;
|
|
37
|
+
else if (arg === '--verbose' || arg === '-v') { options.verbose = true; options.thinking = 'show'; }
|
|
38
|
+
else if (arg === '--thinking') options.thinking = args[++i] || 'show';
|
|
39
|
+
else if (arg === '--model' || arg === '-m') options.model = args[++i] || options.model;
|
|
40
|
+
else if (arg === '--url' || arg === '-u') options.url = args[++i];
|
|
41
|
+
else if (arg === '--query' || arg === '-q') options.query = args[++i];
|
|
42
|
+
else if (!arg.startsWith('-') && !options.query) { options.query = args.slice(i).join(' '); break; }
|
|
43
|
+
}
|
|
44
|
+
return options;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function waitForLMStudio(baseUrl, timeoutMs = 30000) {
|
|
48
|
+
const client = new LMStudioClient({ baseUrl });
|
|
49
|
+
const start = Date.now();
|
|
50
|
+
while (Date.now() - start < timeoutMs) {
|
|
51
|
+
const health = await client.checkConnection();
|
|
52
|
+
if (health.connected) return health;
|
|
53
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function attemptAutoStartLMStudio(baseUrl, model) {
|
|
59
|
+
const isWin = process.platform === 'win32';
|
|
60
|
+
const isMac = process.platform === 'darwin';
|
|
61
|
+
|
|
62
|
+
const candidates = isWin
|
|
63
|
+
? resolveDynamicWindowsAppPaths('LM Studio', 'LM Studio.exe')
|
|
64
|
+
: isMac
|
|
65
|
+
? ['/Applications/LM Studio.app/Contents/MacOS/LM Studio']
|
|
66
|
+
: ['lmstudio', '/usr/local/bin/lmstudio', '/opt/lmstudio/bin/lmstudio'];
|
|
67
|
+
|
|
68
|
+
const exe = candidates.find(p => {
|
|
69
|
+
if (p.includes('/') || p.includes('\\')) {
|
|
70
|
+
try { return existsSync(p); } catch { return false; }
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!exe) return null;
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
let port = '1234';
|
|
79
|
+
try { const parsedUrl = new URL(baseUrl); if (parsedUrl.port) port = parsedUrl.port; } catch {}
|
|
80
|
+
|
|
81
|
+
const child = spawn(exe, isWin
|
|
82
|
+
? ['--model', model, '--serve', '--port', port]
|
|
83
|
+
: ['serve', '--model', model, '--port', port],
|
|
84
|
+
{ detached: true, stdio: 'ignore', windowsHide: true }
|
|
85
|
+
);
|
|
86
|
+
if (child.pid) {
|
|
87
|
+
registerBackgroundProcess('lmstudio', child, {
|
|
88
|
+
command: exe,
|
|
89
|
+
args: isWin ? ['--model', model, '--serve', '--port', port] : ['serve', '--model', model, '--port', port],
|
|
90
|
+
metadata: { model, port },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
child.unref();
|
|
94
|
+
|
|
95
|
+
return await waitForLMStudio(baseUrl, 45000);
|
|
96
|
+
} catch { return null; }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function printHelpText() {
|
|
100
|
+
const commands = COMMAND_DEFINITIONS
|
|
101
|
+
.map(command => ` ${C.emerald}${command.usage.padEnd(30)}${C.reset} ${command.desc}`)
|
|
102
|
+
.join('\n');
|
|
103
|
+
console.log(`\n ${C.bold}${C.gold}${UI_ICONS.help} Kiku AI Agent — ${COMMAND_DEFINITIONS.length} Commands${C.reset}\n${commands}\n ${C.dim}Tip: Press [Tab] for auto-completion.${C.reset}\n`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function printStatsText() {
|
|
107
|
+
const { executeTool } = await import('../tools.js');
|
|
108
|
+
const result = await executeTool('get_system_stats', {});
|
|
109
|
+
const s = result.stats;
|
|
110
|
+
console.log(JSON.stringify(s, null, 2));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function main() {
|
|
114
|
+
const opts = parseCliArgs();
|
|
115
|
+
|
|
116
|
+
if (opts.version) { console.log(PACKAGE_VERSION); process.exit(0); }
|
|
117
|
+
if (opts.help) { printHelpText(); process.exit(0); }
|
|
118
|
+
if (opts.showStats) { await printStatsText(); process.exit(0); }
|
|
119
|
+
|
|
120
|
+
if (opts.showTools) {
|
|
121
|
+
console.log(`\n ${C.bold}${C.sakura}Tools (${toolsSchema.length})${C.reset}\n`);
|
|
122
|
+
for (const [i, t] of toolsSchema.entries()) {
|
|
123
|
+
console.log(` ${C.gold}${String(i + 1).padStart(2)}${C.reset} ${C.cyberCyan}${t.function.name}${C.reset} — ${C.dim}${t.function.description.slice(0, 60)}${C.reset}`);
|
|
124
|
+
}
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const baseUrl = opts.url || config.lmStudio.baseUrl;
|
|
129
|
+
const client = new LMStudioClient({ baseUrl, model: opts.model });
|
|
130
|
+
const health = await client.checkConnection();
|
|
131
|
+
|
|
132
|
+
if (!health.connected) {
|
|
133
|
+
console.log(` ${C.amber}!! LM Studio offline${C.reset}`);
|
|
134
|
+
console.log(` ${C.dim}• ${health.error}${C.reset}\n`);
|
|
135
|
+
|
|
136
|
+
const autoHealth = await attemptAutoStartLMStudio(baseUrl, opts.model || config.lmStudio.model);
|
|
137
|
+
if (autoHealth) {
|
|
138
|
+
console.log(` ${C.emerald}[OK] LM Studio started.${C.reset}\n`);
|
|
139
|
+
} else {
|
|
140
|
+
console.log(` ${C.sakura}Setup: Open LM Studio → load google/gemma-4-e4b → Start Server :1234${C.reset}\n`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const agent = new KikuAgent({
|
|
146
|
+
baseUrl,
|
|
147
|
+
model: health.activeModel || opts.model,
|
|
148
|
+
thinkingMode: opts.thinking,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await agent._ready;
|
|
152
|
+
|
|
153
|
+
if (opts.query) {
|
|
154
|
+
const { executeTool: execTool } = await import('../tools.js');
|
|
155
|
+
const { sanitizeQuery } = await import('../sanitizer.js');
|
|
156
|
+
const { sanitized } = sanitizeQuery(opts.query);
|
|
157
|
+
const prompt = sanitized || opts.query;
|
|
158
|
+
|
|
159
|
+
console.log(` ${C.bold}${C.gold}QUERY${C.reset} ${prompt}\n`);
|
|
160
|
+
|
|
161
|
+
await agent.ask(prompt, {
|
|
162
|
+
onReasoningStart: () => process.stdout.write(' THINKING '),
|
|
163
|
+
onReasoningDelta: (chunk) => process.stdout.write(chunk),
|
|
164
|
+
onReasoningEnd: () => process.stdout.write('\n'),
|
|
165
|
+
onToolStart: (name) => process.stdout.write(` [RUNNING] ${name}... `),
|
|
166
|
+
onToolResult: () => process.stdout.write(`[OK]\n`),
|
|
167
|
+
onTokenDelta: (chunk) => process.stdout.write(chunk),
|
|
168
|
+
onFinalAnswer: () => {},
|
|
169
|
+
onError: (err) => console.error(`\n [ERROR] ${err.message}`),
|
|
170
|
+
});
|
|
171
|
+
process.exit(0);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const helpFn = (sub) => { printHelpText(); };
|
|
175
|
+
const adFn = () => { console.log(` ${UI_ICONS.sponsor} SPONSOR DashSecurity — https://dashsecurity.kpltgroup.com/`); };
|
|
176
|
+
|
|
177
|
+
const { waitUntilExit } = render(
|
|
178
|
+
<App
|
|
179
|
+
agent={agent}
|
|
180
|
+
client={client}
|
|
181
|
+
baseUrl={baseUrl}
|
|
182
|
+
printHelp={helpFn}
|
|
183
|
+
printAd={adFn}
|
|
184
|
+
/>,
|
|
185
|
+
{
|
|
186
|
+
exitOnCtrlC: true,
|
|
187
|
+
patchConsole: false,
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
await waitUntilExit;
|
|
192
|
+
|
|
193
|
+
try { await agent.endSession(); } catch {}
|
|
194
|
+
console.log('\n Session archived. Goodbye. (鞠躬 ~ 谢谢!)\n');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
main().catch(err => {
|
|
198
|
+
console.error(`\n ${C.red}Fatal: ${err.message}${C.reset}\n`);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
});
|
|
@@ -3,8 +3,9 @@ function errorMessage(error) {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export class AgentJobManager {
|
|
6
|
-
constructor(limit = 50) {
|
|
6
|
+
constructor(limit = 50, maxConcurrentHeavy = 2) {
|
|
7
7
|
this.limit = limit;
|
|
8
|
+
this.maxConcurrentHeavy = maxConcurrentHeavy;
|
|
8
9
|
this.jobs = [];
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -28,6 +29,15 @@ export class AgentJobManager {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
async run(type, label, runner, options = {}) {
|
|
32
|
+
const isHeavy = type === 'research' || type === 'verify';
|
|
33
|
+
const limit = options.maxConcurrent ?? (isHeavy ? this.maxConcurrentHeavy : Infinity);
|
|
34
|
+
if (Number.isFinite(limit)) {
|
|
35
|
+
const activeCount = this.jobs.filter(j => (j.type === type || (isHeavy && (j.type === 'research' || j.type === 'verify'))) && j.state === 'running').length;
|
|
36
|
+
if (activeCount >= limit) {
|
|
37
|
+
throw new Error(`Too many concurrent ${type} tasks running (${activeCount}/${limit}). Please wait for the active task to complete.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
const job = this.create(type, label);
|
|
32
42
|
const abortParent = () => job.controller.abort(options.signal?.reason);
|
|
33
43
|
options.signal?.addEventListener('abort', abortParent, { once: true });
|