kiku-agent 1.0.9 → 1.0.11
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 +1 -1
- package/package.json +7 -6
- package/server/agent/agentCore.js +116 -66
- package/server/agent/appPaths.js +2 -0
- package/server/agent/cli.js +457 -248
- package/server/agent/commandRegistry.js +370 -41
- package/server/agent/commands.js +217 -45
- package/server/agent/config.js +367 -216
- package/server/agent/doctor.js +1 -1
- package/server/agent/errors.js +205 -0
- package/server/agent/llmClient.js +369 -351
- package/server/agent/queryDetails.js +234 -182
- package/server/agent/session.js +410 -244
- package/server/agent/terminalImage.js +108 -2
- package/server/agent/ui.js +54 -44
- package/src/assets/images/0040jbadgy1igaiagw3ezj61s02ebu0x02.jpg +0 -0
- package/src/assets/images/0040jbadgy1igaiaivng3j61rv2ebx6p02.jpg +0 -0
- package/src/assets/images/0040jbadgy1igaiajuixvj62bw340qv502.jpg +0 -0
- package/src/assets/images/0040jbadgy1igdxrcipx4j61k422wtpp02.jpg +0 -0
- package/src/assets/images/0040jbadgy1igdxrg3cq5j62bw340u0x02.jpg +0 -0
- package/src/assets/images/0040jbadgy1igdy9hpg8aj62c0340hdt02.jpg +0 -0
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ Automatic installation is available for global npm installs. Source checkouts, l
|
|
|
87
87
|
|
|
88
88
|
After an update or rollback, restart `kiku-agent` and any application hosting `kiku-mcp`. Update settings and rollback history are stored in the normal Kiku user data directory as `update-state.json`; sessions, memory, `.env`, and YouTube cookies are not modified.
|
|
89
89
|
|
|
90
|
-
For a local checkout before the package is published, use `npm pack` followed by `npm install -g ./kiku-agent-1.0.
|
|
90
|
+
For a local checkout before the package is published, use `npm pack` followed by `npm install -g ./kiku-agent-1.0.11.tgz`.
|
|
91
91
|
|
|
92
92
|
### ✨ Features
|
|
93
93
|
- **LM Studio Integration**: Connects seamlessly to LM Studio's OpenAI-compatible server at `http://127.0.0.1:1234/v1` (default model `google/gemma-4-e4b`, with auto-detection of loaded models).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kiku-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Kiku AI terminal agent and MCP server for Ju Jingyi knowledge, media, and career data.",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"type": "module",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"kikuUpdate": {
|
|
30
30
|
"channel": "stable",
|
|
31
31
|
"releaseSummary": [
|
|
32
|
-
"Added
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
32
|
+
"Added session restore and resume support",
|
|
33
|
+
"Fixed CJK fullwidth table wrapping in TUI",
|
|
34
|
+
"Enhanced React 19 rendering safety",
|
|
35
|
+
"Added comprehensive version bump tool"
|
|
36
36
|
],
|
|
37
37
|
"releaseUrl": "https://www.npmjs.com/package/kiku-agent"
|
|
38
38
|
},
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
"kiku-agent": "node server/agent/cli.js",
|
|
64
64
|
"kiku-mcp": "node server/mcp/stdio.js",
|
|
65
65
|
"kiku-ink": "npx tsx server/agent/ink/main.jsx",
|
|
66
|
-
"test": "node --test server/agent/tests/*.test.js server/mcp/tests/*.test.js"
|
|
66
|
+
"test": "node --test server/agent/tests/*.test.js server/mcp/tests/*.test.js",
|
|
67
|
+
"bump": "node bump_version.js"
|
|
67
68
|
},
|
|
68
69
|
"dependencies": {
|
|
69
70
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
@@ -12,8 +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';
|
|
16
|
-
import { AgentJobManager } from './jobManager.js';
|
|
15
|
+
import { contextCompactor } from './contextCompactor.js';
|
|
16
|
+
import { AgentJobManager } from './jobManager.js';
|
|
17
17
|
|
|
18
18
|
export function detectDominantLanguage(text) {
|
|
19
19
|
if (!text || typeof text !== 'string') return 'th';
|
|
@@ -64,8 +64,8 @@ export class KikuAgent {
|
|
|
64
64
|
this.mcpManager = options.mcpManager || new McpClientManager();
|
|
65
65
|
this.router = new DynamicToolRouter(this.getAllToolsSchema());
|
|
66
66
|
this.research = new ResearchOrchestrator({ client: this.client });
|
|
67
|
-
this.suggestions = new SuggestionEngine({ client: this.client, memory: this.memory });
|
|
68
|
-
this.jobs = new AgentJobManager();
|
|
67
|
+
this.suggestions = new SuggestionEngine({ client: this.client, memory: this.memory });
|
|
68
|
+
this.jobs = new AgentJobManager();
|
|
69
69
|
this.systemPrompt = this.buildSystemPrompt();
|
|
70
70
|
this.initHistory();
|
|
71
71
|
this.restoredMessageCount = 0;
|
|
@@ -103,39 +103,39 @@ export class KikuAgent {
|
|
|
103
103
|
return this._ready;
|
|
104
104
|
}
|
|
105
105
|
|
|
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);
|
|
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);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
getResearchStatus() {
|
|
132
132
|
return this.research.getStatus();
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
cancelResearch() {
|
|
136
|
-
const direct = this.research.cancel();
|
|
137
|
-
const tracked = this.jobs.cancelType('research') || this.jobs.cancelType('verify');
|
|
138
|
-
return direct || tracked;
|
|
135
|
+
cancelResearch() {
|
|
136
|
+
const direct = this.research.cancel();
|
|
137
|
+
const tracked = this.jobs.cancelType('research') || this.jobs.cancelType('verify');
|
|
138
|
+
return direct || tracked;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
async generateSuggestions(options = {}) {
|
|
@@ -143,33 +143,33 @@ export class KikuAgent {
|
|
|
143
143
|
return this.suggestions.generateSuggestions(options);
|
|
144
144
|
}
|
|
145
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
|
+
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
|
+
}
|
|
173
173
|
|
|
174
174
|
initHistory() {
|
|
175
175
|
this.conversationHistory = [
|
|
@@ -181,13 +181,7 @@ export class KikuAgent {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
clearMemory() {
|
|
184
|
-
|
|
185
|
-
this.memory.archiveSession(this.session.toSnapshot()).catch(() => { });
|
|
186
|
-
this.memory.consolidateSession(this.session.toSnapshot()).catch(() => { });
|
|
187
|
-
}
|
|
188
|
-
this.initHistory();
|
|
189
|
-
this.session.reset();
|
|
190
|
-
this.session.clearDisk().catch(() => { });
|
|
184
|
+
return this.endSession();
|
|
191
185
|
}
|
|
192
186
|
|
|
193
187
|
async loadSession() {
|
|
@@ -223,6 +217,59 @@ export class KikuAgent {
|
|
|
223
217
|
}
|
|
224
218
|
}
|
|
225
219
|
|
|
220
|
+
async restoreSession(sessionId) {
|
|
221
|
+
await this._ready;
|
|
222
|
+
if (!sessionId) return null;
|
|
223
|
+
|
|
224
|
+
let targetSessionId = String(sessionId).trim();
|
|
225
|
+
const archives = this.memory.getArchivedSessions(50);
|
|
226
|
+
if (/^\d+$/.test(targetSessionId)) {
|
|
227
|
+
const idx = parseInt(targetSessionId, 10) - 1;
|
|
228
|
+
if (archives[idx]) {
|
|
229
|
+
targetSessionId = archives[idx].id;
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
const match = archives.find(s => s.id === targetSessionId || s.id.toLowerCase().includes(targetSessionId.toLowerCase()));
|
|
233
|
+
if (match) {
|
|
234
|
+
targetSessionId = match.id;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const archived = await this.memory.loadArchivedSession(targetSessionId);
|
|
239
|
+
if (!archived) return null;
|
|
240
|
+
|
|
241
|
+
if (this.session.messages.length > 0 && this.session.id !== targetSessionId) {
|
|
242
|
+
await this.memory.archiveSession(this.session.toSnapshot()).catch(() => {});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.session.restoreFromSnapshot(archived);
|
|
246
|
+
await this.session.saveToDisk().catch(() => {});
|
|
247
|
+
|
|
248
|
+
this.initHistory();
|
|
249
|
+
for (const msg of this.session.messages) {
|
|
250
|
+
if (msg.role === 'user') {
|
|
251
|
+
const textPart = msg.parts?.find(p => p.type === 'text');
|
|
252
|
+
if (textPart?.content) {
|
|
253
|
+
this.conversationHistory.push({
|
|
254
|
+
role: 'user',
|
|
255
|
+
content: textPart.content
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
} else if (msg.role === 'assistant') {
|
|
259
|
+
const textPart = msg.parts?.find(p => p.type === 'text');
|
|
260
|
+
if (textPart?.content) {
|
|
261
|
+
this.conversationHistory.push({
|
|
262
|
+
role: 'assistant',
|
|
263
|
+
content: textPart.content
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
this.restoredMessageCount = this.session.messages.length;
|
|
269
|
+
eventBus.emit(Events.SESSION_SAVED, { sessionId: this.session.id });
|
|
270
|
+
return archived;
|
|
271
|
+
}
|
|
272
|
+
|
|
226
273
|
getEnrichedSystemPrompt() {
|
|
227
274
|
const memoryContext = this.memory.buildMemoryContext();
|
|
228
275
|
return this.systemPrompt + memoryContext;
|
|
@@ -507,7 +554,10 @@ ${toolsSummary}
|
|
|
507
554
|
|
|
508
555
|
this.applySlidingWindow();
|
|
509
556
|
|
|
510
|
-
const currentAssistantSessionMsg = this.session.createAssistantMessage(
|
|
557
|
+
const currentAssistantSessionMsg = this.session.createAssistantMessage({
|
|
558
|
+
model: this.client?.model || null,
|
|
559
|
+
provider: this.client?.providerName || this.client?.provider || null,
|
|
560
|
+
});
|
|
511
561
|
|
|
512
562
|
let currentIteration = 0;
|
|
513
563
|
const toolResultCache = new Map();
|
package/server/agent/appPaths.js
CHANGED
|
@@ -19,3 +19,5 @@ export function getKikuDataDir(env = process.env, platform = process.platform) {
|
|
|
19
19
|
export const KIKU_DATA_DIR = getKikuDataDir();
|
|
20
20
|
export const SESSION_DIR = path.join(KIKU_DATA_DIR, 'sessions');
|
|
21
21
|
export const EXPORT_DIR = path.join(KIKU_DATA_DIR, 'exports');
|
|
22
|
+
export const PROVIDER_KEYS_FILE = path.join(KIKU_DATA_DIR, 'provider_keys.json');
|
|
23
|
+
export const SETTINGS_FILE = path.join(KIKU_DATA_DIR, 'settings.json');
|