kiku-agent 1.0.6 → 1.0.8
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/LICENSE +621 -0
- package/README.md +317 -31
- package/package.json +96 -93
- package/server/agent/agentCore.js +58 -31
- package/server/agent/cli.js +101 -56
- package/server/agent/commandFeatures.js +517 -0
- package/server/agent/commandInput.js +113 -0
- package/server/agent/commandRegistry.js +124 -10
- package/server/agent/commands.js +383 -10
- package/server/agent/config.js +64 -48
- package/server/agent/jobManager.js +96 -0
- package/server/agent/llmClient.js +26 -19
- package/server/agent/mcpClient.js +68 -11
- package/server/agent/memory.js +87 -14
- package/server/agent/modelManager.js +30 -13
- package/server/agent/quizData.js +384 -0
- package/server/agent/terminalImage.js +248 -0
- package/server/agent/tools.js +153 -43
- package/server/agent/ui.js +67 -21
- package/server/agent/youtubeAuth.js +1 -2
- package/src/assets/images/0040jbadgy1id6amcqte3j62c0340qv602.jpg +0 -0
- package/src/assets/images/0040jbadly8icq3if7twwj60qy0qy0uc02.jpg +0 -0
package/package.json
CHANGED
|
@@ -1,93 +1,96 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "kiku-agent",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Kiku AI terminal agent and MCP server for Ju Jingyi knowledge, media, and career data.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"kiku-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"./
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"server/
|
|
18
|
-
"server/mcp
|
|
19
|
-
"server/mcp
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"kiku"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"kiku-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"@
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"ink
|
|
85
|
-
"
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "kiku-agent",
|
|
3
|
+
"version": "1.0.8",
|
|
4
|
+
"description": "Kiku AI terminal agent and MCP server for Ju Jingyi knowledge, media, and career data.",
|
|
5
|
+
"license": "GPL-3.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kiku-agent": "server/agent/cli.js",
|
|
9
|
+
"kiku-mcp": "server/mcp/stdio.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./server/agent/agentCore.js",
|
|
13
|
+
"./mcp": "./server/mcp/server.js",
|
|
14
|
+
"./tools": "./server/agent/tools.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"server/agent/*.js",
|
|
18
|
+
"server/mcp/*.js",
|
|
19
|
+
"server/mcp/data/*.js",
|
|
20
|
+
"server/mcp/**/*.json",
|
|
21
|
+
"src/data/**/*.js",
|
|
22
|
+
"src/assets/images/**/*",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20.0.0"
|
|
28
|
+
},
|
|
29
|
+
"kikuUpdate": {
|
|
30
|
+
"channel": "stable",
|
|
31
|
+
"releaseSummary": [
|
|
32
|
+
"Updated production model defaults and live fallback resolution across cloud providers",
|
|
33
|
+
"Hardened REST API key validation and isolated rate-limit probes",
|
|
34
|
+
"Fixed discography filtering, MCP configuration isolation, and environment loading order",
|
|
35
|
+
"Secured YouTube iframe messaging and expanded provider and API regression coverage"
|
|
36
|
+
],
|
|
37
|
+
"releaseUrl": "https://www.npmjs.com/package/kiku-agent"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"kiku",
|
|
41
|
+
"ju-jingyi",
|
|
42
|
+
"cli",
|
|
43
|
+
"ai-agent",
|
|
44
|
+
"mcp",
|
|
45
|
+
"model-context-protocol",
|
|
46
|
+
"lm-studio"
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/ThemeHackers/jujingyi_kikuuu.git"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://jujingyi-kikuuu.vercel.app/",
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/ThemeHackers/jujingyi_kikuuu/issues"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"dev": "vite",
|
|
61
|
+
"build": "vite build",
|
|
62
|
+
"preview": "vite preview",
|
|
63
|
+
"kiku-agent": "node server/agent/cli.js",
|
|
64
|
+
"kiku-mcp": "node server/mcp/stdio.js",
|
|
65
|
+
"kiku-ink": "npx tsx server/agent/ink/main.jsx",
|
|
66
|
+
"test": "node --test server/agent/tests/*.test.js server/mcp/tests/*.test.js"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
70
|
+
"clsx": "^2.1.1",
|
|
71
|
+
"framer-motion": "^12.4.7",
|
|
72
|
+
"jpeg-js": "^0.4.4",
|
|
73
|
+
"lucide-react": "^1.16.0",
|
|
74
|
+
"react": "^19.0.0",
|
|
75
|
+
"react-dom": "^19.0.0",
|
|
76
|
+
"tailwind-merge": "^3.0.2",
|
|
77
|
+
"zod": "^4.4.3"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@tailwindcss/vite": "^4.0.9",
|
|
81
|
+
"@types/react": "^19.0.10",
|
|
82
|
+
"@types/react-dom": "^19.0.4",
|
|
83
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
84
|
+
"ink": "^7.1.1",
|
|
85
|
+
"ink-select-input": "^6.2.0",
|
|
86
|
+
"ink-spinner": "^5.0.0",
|
|
87
|
+
"ink-text-input": "^6.0.0",
|
|
88
|
+
"tailwindcss": "^4.0.9",
|
|
89
|
+
"tsx": "^4.23.12",
|
|
90
|
+
"vite": "^6.2.0"
|
|
91
|
+
},
|
|
92
|
+
"allowScripts": {
|
|
93
|
+
"esbuild@0.25.12": true,
|
|
94
|
+
"esbuild@0.28.2": true
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -12,7 +12,8 @@ import { ResearchOrchestrator } from './research.js';
|
|
|
12
12
|
import { SuggestionEngine } from './suggestions.js';
|
|
13
13
|
import { McpClientManager } from './mcpClient.js';
|
|
14
14
|
import { DynamicToolRouter } from './toolRouter.js';
|
|
15
|
-
import { contextCompactor } from './contextCompactor.js';
|
|
15
|
+
import { contextCompactor } from './contextCompactor.js';
|
|
16
|
+
import { AgentJobManager } from './jobManager.js';
|
|
16
17
|
|
|
17
18
|
export function detectDominantLanguage(text) {
|
|
18
19
|
if (!text || typeof text !== 'string') return 'th';
|
|
@@ -63,7 +64,8 @@ export class KikuAgent {
|
|
|
63
64
|
this.mcpManager = options.mcpManager || new McpClientManager();
|
|
64
65
|
this.router = new DynamicToolRouter(this.getAllToolsSchema());
|
|
65
66
|
this.research = new ResearchOrchestrator({ client: this.client });
|
|
66
|
-
this.suggestions = new SuggestionEngine({ client: this.client, memory: this.memory });
|
|
67
|
+
this.suggestions = new SuggestionEngine({ client: this.client, memory: this.memory });
|
|
68
|
+
this.jobs = new AgentJobManager();
|
|
67
69
|
this.systemPrompt = this.buildSystemPrompt();
|
|
68
70
|
this.initHistory();
|
|
69
71
|
this.restoredMessageCount = 0;
|
|
@@ -101,33 +103,39 @@ export class KikuAgent {
|
|
|
101
103
|
return this._ready;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
async runSubagent(task, options = {}) {
|
|
105
|
-
await this._ready;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
})
|
|
106
|
+
async runSubagent(task, options = {}) {
|
|
107
|
+
await this._ready;
|
|
108
|
+
return this.jobs.run('subagent', task, async ({ signal }) => {
|
|
109
|
+
const subagent = new ResearchSubagent({
|
|
110
|
+
client: this.client,
|
|
111
|
+
maxIterations: options.maxIterations || 3,
|
|
112
|
+
});
|
|
113
|
+
return subagent.run(task, {
|
|
114
|
+
signal,
|
|
115
|
+
onProgress: options.onProgress,
|
|
116
|
+
skillContext: this.memory.buildUserSkillContext(),
|
|
117
|
+
});
|
|
118
|
+
}, options);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async runResearch(question, options = {}) {
|
|
122
|
+
await this._ready;
|
|
123
|
+
const type = options.mode === 'verify' ? 'verify' : 'research';
|
|
124
|
+
return this.jobs.run(type, question, ({ signal }) => this.research.run(question, {
|
|
125
|
+
...options,
|
|
126
|
+
signal,
|
|
127
|
+
skillContext: this.memory.buildUserSkillContext(),
|
|
128
|
+
}), options);
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
getResearchStatus() {
|
|
126
132
|
return this.research.getStatus();
|
|
127
133
|
}
|
|
128
134
|
|
|
129
|
-
cancelResearch() {
|
|
130
|
-
|
|
135
|
+
cancelResearch() {
|
|
136
|
+
const direct = this.research.cancel();
|
|
137
|
+
const tracked = this.jobs.cancelType('research') || this.jobs.cancelType('verify');
|
|
138
|
+
return direct || tracked;
|
|
131
139
|
}
|
|
132
140
|
|
|
133
141
|
async generateSuggestions(options = {}) {
|
|
@@ -135,14 +143,33 @@ export class KikuAgent {
|
|
|
135
143
|
return this.suggestions.generateSuggestions(options);
|
|
136
144
|
}
|
|
137
145
|
|
|
138
|
-
async runSuggestionBatch(targets, options = {}) {
|
|
139
|
-
await this._ready;
|
|
140
|
-
return this.suggestions.runBatchSubagents(targets,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
async runSuggestionBatch(targets, options = {}) {
|
|
147
|
+
await this._ready;
|
|
148
|
+
return this.jobs.run('suggestion', String(targets || 'all'), ({ signal }) => this.suggestions.runBatchSubagents(targets, {
|
|
149
|
+
...options,
|
|
150
|
+
signal,
|
|
151
|
+
}), options);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
getLastSuggestions() {
|
|
155
|
+
return this.suggestions.getLastSuggestions();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
getJobs() {
|
|
159
|
+
return this.jobs.list();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
getJob(id) {
|
|
163
|
+
return this.jobs.get(id);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
cancelJob(id) {
|
|
167
|
+
return this.jobs.cancel(id);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
clearJobs() {
|
|
171
|
+
return this.jobs.clear();
|
|
172
|
+
}
|
|
146
173
|
|
|
147
174
|
initHistory() {
|
|
148
175
|
this.conversationHistory = [
|
package/server/agent/cli.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import readline from 'node:readline';
|
|
4
|
-
import { stdin as input } from 'node:process';
|
|
5
|
-
import { existsSync } from 'node:fs';
|
|
6
|
-
import { spawn } from 'node:child_process';
|
|
7
|
-
import
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
import { stdin as input } from 'node:process';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import './youtubeAuth.js';
|
|
8
|
+
import { KikuAgent } from './agentCore.js';
|
|
8
9
|
import { LLMClient, LMStudioClient } from './llmClient.js';
|
|
9
10
|
import { toolsSchema, toolHandlers, executeTool } from './tools.js';
|
|
10
11
|
import { config, CLOUD_PROVIDERS } from './config.js';
|
|
@@ -16,8 +17,9 @@ import { sanitizeQuery } from './sanitizer.js';
|
|
|
16
17
|
import { isAbortError } from './errors.js';
|
|
17
18
|
import { COMMAND_DEFINITIONS, SUB_COMMANDS, findCommandDefinition, getCommandDetails } from './commandRegistry.js';
|
|
18
19
|
import { ModelManager } from './modelManager.js';
|
|
19
|
-
import { PACKAGE_VERSION } from './version.js';
|
|
20
|
-
import { getTheme, getThemeName } from './theme.js';
|
|
20
|
+
import { PACKAGE_VERSION } from './version.js';
|
|
21
|
+
import { getTheme, getThemeName } from './theme.js';
|
|
22
|
+
import { createTerminalImageGallery } from './terminalImage.js';
|
|
21
23
|
import {
|
|
22
24
|
classifyToolResult,
|
|
23
25
|
formatDetailDuration,
|
|
@@ -37,7 +39,7 @@ import {
|
|
|
37
39
|
printWelcomeHero, getWelcomeHeroLines, randomFanName, setupOutputInterception,
|
|
38
40
|
rawWrite, INPUT_PLACEHOLDER, UI_ICONS,
|
|
39
41
|
spinnerFrames, thinkingFrames, createProgressRunner,
|
|
40
|
-
enterAlternateScreen, exitAlternateScreen, getTuiViewportLayout, VirtualScreenBuffer,
|
|
42
|
+
enterAlternateScreen, exitAlternateScreen, getTuiViewportLayout, getNewOutputScrollOffset, VirtualScreenBuffer,
|
|
41
43
|
} from './ui.js';
|
|
42
44
|
|
|
43
45
|
let activeAbortController = null;
|
|
@@ -489,7 +491,11 @@ function printAd() {
|
|
|
489
491
|
|
|
490
492
|
class InteractiveTuiPrompt {
|
|
491
493
|
constructor(options = {}) {
|
|
492
|
-
this.
|
|
494
|
+
this.defaultPromptText = options.prompt || 'Kiku ❯ ';
|
|
495
|
+
this.promptText = this.defaultPromptText;
|
|
496
|
+
this.inputPlaceholder = INPUT_PLACEHOLDER;
|
|
497
|
+
this.recordInputHistory = true;
|
|
498
|
+
this.cancelValue = null;
|
|
493
499
|
this.agent = options.agent || null;
|
|
494
500
|
this.modelName = options.modelName || 'gemma-4-e4b';
|
|
495
501
|
this.provider = options.provider || 'lmstudio';
|
|
@@ -520,27 +526,28 @@ class InteractiveTuiPrompt {
|
|
|
520
526
|
);
|
|
521
527
|
}
|
|
522
528
|
|
|
523
|
-
addViewportLines(lines) {
|
|
524
|
-
if (lines === null || lines === undefined) return;
|
|
525
|
-
if (!Array.isArray(lines)) lines = [lines];
|
|
526
|
-
const wasLive = this.scrollOffset === 0;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
}
|
|
529
|
+
addViewportLines(lines) {
|
|
530
|
+
if (lines === null || lines === undefined) return;
|
|
531
|
+
if (!Array.isArray(lines)) lines = [lines];
|
|
532
|
+
const wasLive = this.scrollOffset === 0;
|
|
533
|
+
let addedLineCount = 0;
|
|
534
|
+
for (const l of lines) {
|
|
535
|
+
if (typeof l === 'string') {
|
|
536
|
+
const sublines = l.split('\n');
|
|
537
|
+
for (const sl of sublines) {
|
|
538
|
+
this.viewportLines.push(sl);
|
|
539
|
+
addedLineCount += 1;
|
|
540
|
+
}
|
|
541
|
+
} else if (l != null) {
|
|
542
|
+
this.viewportLines.push(String(l));
|
|
543
|
+
addedLineCount += 1;
|
|
544
|
+
}
|
|
536
545
|
}
|
|
537
546
|
if (this.viewportLines.length > 5000) {
|
|
538
547
|
const removedCount = this.viewportLines.length - 5000;
|
|
539
548
|
this.viewportLines.splice(0, removedCount);
|
|
540
549
|
}
|
|
541
|
-
|
|
542
|
-
this.scrollOffset = 0;
|
|
543
|
-
}
|
|
550
|
+
this.scrollOffset = getNewOutputScrollOffset(addedLineCount, process.stdout.rows || 24, wasLive ? 0 : this.scrollOffset);
|
|
544
551
|
this.render();
|
|
545
552
|
}
|
|
546
553
|
|
|
@@ -577,10 +584,15 @@ class InteractiveTuiPrompt {
|
|
|
577
584
|
try { if (input.isTTY) input.setRawMode(false); } catch { }
|
|
578
585
|
}
|
|
579
586
|
|
|
580
|
-
async readLine() {
|
|
581
|
-
return new Promise((resolve, reject) => {
|
|
582
|
-
this._cleanupInput();
|
|
583
|
-
|
|
587
|
+
async readLine(options = {}) {
|
|
588
|
+
return new Promise((resolve, reject) => {
|
|
589
|
+
this._cleanupInput();
|
|
590
|
+
const inputOptions = typeof options === 'string' ? { prompt: options } : options;
|
|
591
|
+
this.promptText = inputOptions.prompt || this.defaultPromptText;
|
|
592
|
+
this.inputPlaceholder = inputOptions.placeholder || INPUT_PLACEHOLDER;
|
|
593
|
+
this.recordInputHistory = inputOptions.history !== false;
|
|
594
|
+
this.cancelValue = inputOptions.cancelValue ?? null;
|
|
595
|
+
this.line = '';
|
|
584
596
|
this.cursor = 0;
|
|
585
597
|
this.historyIndex = -1;
|
|
586
598
|
this.popoverIndex = 0;
|
|
@@ -614,7 +626,7 @@ class InteractiveTuiPrompt {
|
|
|
614
626
|
this.cursor = 0;
|
|
615
627
|
this.popoverActive = false;
|
|
616
628
|
this.popoverItems = [];
|
|
617
|
-
if (result && result.trim()) this.history.push(result);
|
|
629
|
+
if (this.recordInputHistory && result && result.trim()) this.history.push(result);
|
|
618
630
|
const resolve = this.activeResolve;
|
|
619
631
|
this.activeResolve = null;
|
|
620
632
|
this.activeReject = null;
|
|
@@ -783,7 +795,7 @@ class InteractiveTuiPrompt {
|
|
|
783
795
|
trailingStyled = `${C.dim}${C.slate}${ghostDisplay}${C.reset}`;
|
|
784
796
|
}
|
|
785
797
|
} else if (!this.line) {
|
|
786
|
-
const placeholder = sliceLineForDisplay(
|
|
798
|
+
const placeholder = sliceLineForDisplay(this.inputPlaceholder, 0, maxLineWidth).displayLine;
|
|
787
799
|
trailingStyled = `${C.dim}${C.slate}${placeholder}${C.reset}`;
|
|
788
800
|
}
|
|
789
801
|
|
|
@@ -800,8 +812,12 @@ class InteractiveTuiPrompt {
|
|
|
800
812
|
handleKeypress(str, key) {
|
|
801
813
|
if (!key && !str) return;
|
|
802
814
|
|
|
803
|
-
if ((key?.ctrl && key?.name === 'c') || str === '\x03') {
|
|
804
|
-
if (
|
|
815
|
+
if ((key?.ctrl && key?.name === 'c') || str === '\x03') {
|
|
816
|
+
if (this.cancelValue !== null) {
|
|
817
|
+
this.finish(this.cancelValue);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
if (isProcessing) {
|
|
805
821
|
if (this.onCancel) this.onCancel();
|
|
806
822
|
else if (this.onSigInt) this.onSigInt();
|
|
807
823
|
this.addViewportLines(` ${C.amber}[✓ Cancelled by user]${C.reset}`);
|
|
@@ -826,8 +842,12 @@ class InteractiveTuiPrompt {
|
|
|
826
842
|
return;
|
|
827
843
|
}
|
|
828
844
|
|
|
829
|
-
if (key?.name === 'escape' || str === '\x1b') {
|
|
830
|
-
if (this.
|
|
845
|
+
if (key?.name === 'escape' || str === '\x1b') {
|
|
846
|
+
if (this.cancelValue !== null) {
|
|
847
|
+
this.finish(this.cancelValue);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
if (this.popoverActive) {
|
|
831
851
|
this.popoverActive = false;
|
|
832
852
|
this.popoverItems = [];
|
|
833
853
|
this.ghostText = '';
|
|
@@ -1540,15 +1560,23 @@ async function main() {
|
|
|
1540
1560
|
|
|
1541
1561
|
if (opts.showStats) { printWelcomeHero(); const r = await executeTool('get_system_stats', {}); console.log(JSON.stringify(r, null, 2)); process.exit(0); }
|
|
1542
1562
|
|
|
1543
|
-
if (opts.query) {
|
|
1544
|
-
printWelcomeHero();
|
|
1545
|
-
const client = new LLMClient({
|
|
1563
|
+
if (opts.query) {
|
|
1564
|
+
printWelcomeHero();
|
|
1565
|
+
const client = new LLMClient({
|
|
1546
1566
|
provider: opts.provider || config.activeProvider,
|
|
1547
1567
|
baseUrl: opts.url,
|
|
1548
1568
|
apiKey: opts.apiKey,
|
|
1549
|
-
model: opts.model
|
|
1550
|
-
});
|
|
1551
|
-
|
|
1569
|
+
model: opts.model
|
|
1570
|
+
});
|
|
1571
|
+
const modelManager = new ModelManager(client, { requestedModel: opts.model || client.model });
|
|
1572
|
+
const modelResolution = await modelManager.resolve({ requestedModel: opts.model || client.model });
|
|
1573
|
+
if (!modelResolution.connected || !modelResolution.selectedModel) {
|
|
1574
|
+
throw new Error(modelResolution.error || `No available chat model found for ${client.providerName}`);
|
|
1575
|
+
}
|
|
1576
|
+
if (modelResolution.usedFallback) {
|
|
1577
|
+
console.log(` ${C.amber}Model ${modelResolution.requestedModel} is unavailable; using ${modelResolution.selectedModel}.${C.reset}\n`);
|
|
1578
|
+
}
|
|
1579
|
+
console.log(` ${C.bold}${C.gold}QUERY${C.reset} ${C.white}${opts.query}${C.reset}\n`);
|
|
1552
1580
|
const agent = new KikuAgent({ client, thinkingMode: opts.thinking });
|
|
1553
1581
|
await executeQueryWithUI(agent, opts.query, agent.session.thinkingMode === 'show', null, 1);
|
|
1554
1582
|
process.exit(0);
|
|
@@ -1592,7 +1620,7 @@ async function main() {
|
|
|
1592
1620
|
return false;
|
|
1593
1621
|
}
|
|
1594
1622
|
|
|
1595
|
-
const tuiPrompt = new InteractiveTuiPrompt({
|
|
1623
|
+
const tuiPrompt = new InteractiveTuiPrompt({
|
|
1596
1624
|
prompt: 'Kiku ❯ ',
|
|
1597
1625
|
agent,
|
|
1598
1626
|
modelName: opts.model || client.model || 'gemma-4-e4b',
|
|
@@ -1612,7 +1640,8 @@ async function main() {
|
|
|
1612
1640
|
process.exit(0);
|
|
1613
1641
|
}
|
|
1614
1642
|
}
|
|
1615
|
-
});
|
|
1643
|
+
});
|
|
1644
|
+
const terminalGallery = createTerminalImageGallery();
|
|
1616
1645
|
|
|
1617
1646
|
globalTuiPrompt = tuiPrompt;
|
|
1618
1647
|
setupOutputInterception(tuiPrompt, () => isProcessing);
|
|
@@ -1665,7 +1694,7 @@ async function main() {
|
|
|
1665
1694
|
}
|
|
1666
1695
|
}
|
|
1667
1696
|
|
|
1668
|
-
const modelManager = new ModelManager(client, { requestedModel: opts.model || client.model });
|
|
1697
|
+
const modelManager = new ModelManager(client, { requestedModel: opts.model || client.model });
|
|
1669
1698
|
const modelResolution = catalogOnlyMode
|
|
1670
1699
|
? { connected: false, state: 'catalog_only' }
|
|
1671
1700
|
: await modelManager.resolve({ requestedModel: opts.model || client.model });
|
|
@@ -1685,7 +1714,7 @@ async function main() {
|
|
|
1685
1714
|
title: 'Connected & Ready',
|
|
1686
1715
|
status: 'connected',
|
|
1687
1716
|
lines: [
|
|
1688
|
-
`• Provider: ${client.providerName} (Local) • Model: ${modelResolution.selectedModel}`,
|
|
1717
|
+
`• Provider: ${client.providerName}${client.provider === 'lmstudio' ? ' (Local)' : ''} • Model: ${modelResolution.selectedModel}`,
|
|
1689
1718
|
`• Status: Chat & Tool DAG Active • Tools: ${toolsSchema.length} Loaded`,
|
|
1690
1719
|
],
|
|
1691
1720
|
});
|
|
@@ -1734,9 +1763,17 @@ async function main() {
|
|
|
1734
1763
|
|
|
1735
1764
|
const mcpStatus = agent.mcpManager ? agent.mcpManager.getStatus() : null;
|
|
1736
1765
|
if (mcpStatus && mcpStatus.activeServersCount > 0 && !opts.mcp) {
|
|
1737
|
-
const serverSummaries = mcpStatus.servers
|
|
1738
|
-
.filter(s => s.status === 'connected')
|
|
1739
|
-
.map(s =>
|
|
1766
|
+
const serverSummaries = mcpStatus.servers
|
|
1767
|
+
.filter(s => s.status === 'connected')
|
|
1768
|
+
.map(s => {
|
|
1769
|
+
const sources = (s.sources || [])
|
|
1770
|
+
.map(source => String(source).split(/[\\/]/).pop())
|
|
1771
|
+
.filter(Boolean);
|
|
1772
|
+
const sourceLabel = sources.length > 0
|
|
1773
|
+
? ` • source: ${[...new Set(sources)].join(', ')}`
|
|
1774
|
+
: '';
|
|
1775
|
+
return `• ${s.name} (${s.type}) — ${s.toolsCount} tools${sourceLabel}`;
|
|
1776
|
+
});
|
|
1740
1777
|
printRichCard({
|
|
1741
1778
|
title: 'Persisted MCP Connected',
|
|
1742
1779
|
status: 'mcp',
|
|
@@ -1795,10 +1832,16 @@ async function main() {
|
|
|
1795
1832
|
printHelp,
|
|
1796
1833
|
printQueryDetails,
|
|
1797
1834
|
copyQueryDetails,
|
|
1798
|
-
printWelcome: printWelcomeHero,
|
|
1799
|
-
printAd,
|
|
1800
|
-
|
|
1801
|
-
|
|
1835
|
+
printWelcome: printWelcomeHero,
|
|
1836
|
+
printAd,
|
|
1837
|
+
showTerminalImage: () => {
|
|
1838
|
+
const imageLines = terminalGallery.maybeRender(queryCount, { force: true });
|
|
1839
|
+
if (imageLines.length > 0) tuiPrompt.addViewportLines(imageLines);
|
|
1840
|
+
return imageLines.length > 0;
|
|
1841
|
+
},
|
|
1842
|
+
cancelActiveQuery,
|
|
1843
|
+
readInput: options => tuiPrompt.readLine(options),
|
|
1844
|
+
enqueueQuery: async (prompt, isRetry) => {
|
|
1802
1845
|
queryQueue.push({ id: 'q_' + Date.now(), number: nextQueryNumber++, prompt, addedAt: Date.now() });
|
|
1803
1846
|
triggerQueueProcessing();
|
|
1804
1847
|
},
|
|
@@ -1870,10 +1913,12 @@ async function main() {
|
|
|
1870
1913
|
});
|
|
1871
1914
|
}
|
|
1872
1915
|
} finally {
|
|
1873
|
-
activeAbortController = null;
|
|
1874
|
-
queryCount++;
|
|
1875
|
-
printAd();
|
|
1876
|
-
|
|
1916
|
+
activeAbortController = null;
|
|
1917
|
+
queryCount++;
|
|
1918
|
+
printAd();
|
|
1919
|
+
const imageLines = terminalGallery.maybeRender(queryCount);
|
|
1920
|
+
if (imageLines.length > 0) tuiPrompt.addViewportLines(imageLines);
|
|
1921
|
+
activeQueryNumber = null;
|
|
1877
1922
|
if (globalTuiPrompt) {
|
|
1878
1923
|
globalTuiPrompt.agentState = '';
|
|
1879
1924
|
globalTuiPrompt.render();
|