kimiflare 0.14.0 → 0.15.0
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/dist/index.js +220 -72
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -35,6 +35,8 @@ async function loadConfig() {
|
|
|
35
35
|
const envEffort = readReasoningEffortEnv();
|
|
36
36
|
const envTheme = process.env.KIMI_THEME;
|
|
37
37
|
const envCoauthor = readCoauthorEnv();
|
|
38
|
+
const envCacheStable = process.env.KIMIFLARE_CACHE_STABLE_PROMPTS;
|
|
39
|
+
const cacheStablePrompts = envCacheStable === "0" || envCacheStable === "false" ? false : true;
|
|
38
40
|
if (envAccount && envToken) {
|
|
39
41
|
return {
|
|
40
42
|
accountId: envAccount,
|
|
@@ -44,7 +46,8 @@ async function loadConfig() {
|
|
|
44
46
|
reasoningEffort: envEffort,
|
|
45
47
|
coauthor: envCoauthor?.enabled ?? true,
|
|
46
48
|
coauthorName: envCoauthor?.name,
|
|
47
|
-
coauthorEmail: envCoauthor?.email
|
|
49
|
+
coauthorEmail: envCoauthor?.email,
|
|
50
|
+
cacheStablePrompts
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
53
|
try {
|
|
@@ -60,7 +63,8 @@ async function loadConfig() {
|
|
|
60
63
|
coauthor: envCoauthor?.enabled ?? parsed.coauthor ?? true,
|
|
61
64
|
coauthorName: envCoauthor?.name ?? parsed.coauthorName,
|
|
62
65
|
coauthorEmail: envCoauthor?.email ?? parsed.coauthorEmail,
|
|
63
|
-
mcpServers: parsed.mcpServers
|
|
66
|
+
mcpServers: parsed.mcpServers,
|
|
67
|
+
cacheStablePrompts: parsed.cacheStablePrompts ?? cacheStablePrompts
|
|
64
68
|
};
|
|
65
69
|
}
|
|
66
70
|
} catch {
|
|
@@ -153,6 +157,20 @@ function jsonReplacer(_key, value) {
|
|
|
153
157
|
}
|
|
154
158
|
return value;
|
|
155
159
|
}
|
|
160
|
+
function stableStringify(value, replacer, space) {
|
|
161
|
+
function sortKeys(obj) {
|
|
162
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
163
|
+
if (Array.isArray(obj)) return obj.map(sortKeys);
|
|
164
|
+
const sorted2 = {};
|
|
165
|
+
const keys = Object.keys(obj).sort();
|
|
166
|
+
for (const k of keys) {
|
|
167
|
+
sorted2[k] = sortKeys(obj[k]);
|
|
168
|
+
}
|
|
169
|
+
return sorted2;
|
|
170
|
+
}
|
|
171
|
+
const sorted = sortKeys(value);
|
|
172
|
+
return JSON.stringify(sorted, replacer, space);
|
|
173
|
+
}
|
|
156
174
|
var init_messages = __esm({
|
|
157
175
|
"src/agent/messages.ts"() {
|
|
158
176
|
"use strict";
|
|
@@ -185,13 +203,17 @@ async function* runKimi(opts2) {
|
|
|
185
203
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
186
204
|
let res;
|
|
187
205
|
try {
|
|
206
|
+
const headers = {
|
|
207
|
+
Authorization: `Bearer ${opts2.apiToken}`,
|
|
208
|
+
"Content-Type": "application/json"
|
|
209
|
+
};
|
|
210
|
+
if (opts2.sessionId) {
|
|
211
|
+
headers["X-Session-ID"] = opts2.sessionId;
|
|
212
|
+
}
|
|
188
213
|
res = await fetch(url, {
|
|
189
214
|
method: "POST",
|
|
190
|
-
headers
|
|
191
|
-
|
|
192
|
-
"Content-Type": "application/json"
|
|
193
|
-
},
|
|
194
|
-
body: JSON.stringify(body, jsonReplacer),
|
|
215
|
+
headers,
|
|
216
|
+
body: stableStringify(body, jsonReplacer),
|
|
195
217
|
signal: opts2.signal
|
|
196
218
|
});
|
|
197
219
|
} catch (fetchErr) {
|
|
@@ -451,12 +473,76 @@ async function logCostDebug(entry) {
|
|
|
451
473
|
await mkdir2(debugDir(), { recursive: true });
|
|
452
474
|
await appendFile(debugPath(), JSON.stringify(entry) + "\n", "utf8");
|
|
453
475
|
}
|
|
476
|
+
function serializePrefix(messages) {
|
|
477
|
+
let end = 0;
|
|
478
|
+
while (end < messages.length && messages[end].role === "system") {
|
|
479
|
+
end++;
|
|
480
|
+
}
|
|
481
|
+
return messages.slice(0, end).map((m) => typeof m.content === "string" ? m.content : JSON.stringify(m.content)).join("\n---\n");
|
|
482
|
+
}
|
|
483
|
+
function comparePromptPrefixes(prev, curr) {
|
|
484
|
+
const prevPrefix = prev ? serializePrefix(prev) : "";
|
|
485
|
+
const currPrefix = serializePrefix(curr);
|
|
486
|
+
const totalChars = curr.reduce((sum, m) => {
|
|
487
|
+
if (typeof m.content === "string") return sum + m.content.length;
|
|
488
|
+
if (Array.isArray(m.content)) return sum + m.content.map((p) => p.type === "text" ? p.text.length : 0).reduce((a, b) => a + b, 0);
|
|
489
|
+
return sum;
|
|
490
|
+
}, 0);
|
|
491
|
+
let firstDiffByte = null;
|
|
492
|
+
let changedSegment = null;
|
|
493
|
+
if (prevPrefix !== currPrefix) {
|
|
494
|
+
const minLen = Math.min(prevPrefix.length, currPrefix.length);
|
|
495
|
+
for (let i = 0; i < minLen; i++) {
|
|
496
|
+
if (prevPrefix[i] !== currPrefix[i]) {
|
|
497
|
+
firstDiffByte = i;
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (firstDiffByte === null && prevPrefix.length !== currPrefix.length) {
|
|
502
|
+
firstDiffByte = minLen;
|
|
503
|
+
}
|
|
504
|
+
if (curr.length >= 1 && curr[0].role === "system") {
|
|
505
|
+
const staticLen = typeof curr[0].content === "string" ? curr[0].content.length : JSON.stringify(curr[0].content).length;
|
|
506
|
+
if (firstDiffByte !== null && firstDiffByte < staticLen) {
|
|
507
|
+
changedSegment = "static";
|
|
508
|
+
} else if (curr.length >= 2 && curr[1].role === "system") {
|
|
509
|
+
const sessionLen = typeof curr[1].content === "string" ? curr[1].content.length : JSON.stringify(curr[1].content).length;
|
|
510
|
+
if (firstDiffByte !== null && firstDiffByte < staticLen + 5 + sessionLen) {
|
|
511
|
+
changedSegment = "session";
|
|
512
|
+
} else {
|
|
513
|
+
changedSegment = "dynamic";
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
changedSegment = "dynamic";
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
changedSegment = "dynamic";
|
|
520
|
+
}
|
|
521
|
+
} else {
|
|
522
|
+
changedSegment = "none";
|
|
523
|
+
}
|
|
524
|
+
const staticPrefixChars = curr.length > 0 && curr[0].role === "system" && typeof curr[0].content === "string" ? curr[0].content.length : 0;
|
|
525
|
+
const sessionPrefixChars = curr.length > 1 && curr[1].role === "system" && typeof curr[1].content === "string" ? curr[1].content.length : 0;
|
|
526
|
+
const dynamicSuffixChars = totalChars - staticPrefixChars - sessionPrefixChars;
|
|
527
|
+
return {
|
|
528
|
+
staticPrefixChars,
|
|
529
|
+
sessionPrefixChars,
|
|
530
|
+
dynamicSuffixChars,
|
|
531
|
+
firstDiffByte,
|
|
532
|
+
changedSegment,
|
|
533
|
+
cacheHitRatio: 0
|
|
534
|
+
// populated by caller with actual usage data
|
|
535
|
+
};
|
|
536
|
+
}
|
|
454
537
|
async function logTurnDebug(ctx) {
|
|
455
538
|
const promptSections = analyzePrompt(ctx.messages);
|
|
456
539
|
const promptTotalChars = promptSections.reduce((sum, s) => sum + s.chars, 0);
|
|
457
540
|
const toolStats = buildToolStats(ctx.toolResults);
|
|
458
541
|
const toolTotalRaw = toolStats.reduce((sum, t) => sum + t.rawBytes, 0);
|
|
459
542
|
const toolTotalReduced = toolStats.reduce((sum, t) => sum + t.reducedBytes, 0);
|
|
543
|
+
const cacheDiagnostics = comparePromptPrefixes(ctx.previousMessages, ctx.messages);
|
|
544
|
+
const cachedTokens = ctx.usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
545
|
+
cacheDiagnostics.cacheHitRatio = ctx.usage.prompt_tokens > 0 ? cachedTokens / ctx.usage.prompt_tokens : 0;
|
|
460
546
|
await logCostDebug({
|
|
461
547
|
v: LOG_VERSION,
|
|
462
548
|
ts: now(),
|
|
@@ -469,7 +555,8 @@ async function logTurnDebug(ctx) {
|
|
|
469
555
|
toolStats,
|
|
470
556
|
toolTotalRawBytes: toolTotalRaw,
|
|
471
557
|
toolTotalReducedBytes: toolTotalReduced,
|
|
472
|
-
toolSavingsPct: toolTotalRaw > 0 ? Math.round((toolTotalRaw - toolTotalReduced) / toolTotalRaw * 100) : 0
|
|
558
|
+
toolSavingsPct: toolTotalRaw > 0 ? Math.round((toolTotalRaw - toolTotalReduced) / toolTotalRaw * 100) : 0,
|
|
559
|
+
cacheDiagnostics
|
|
473
560
|
});
|
|
474
561
|
}
|
|
475
562
|
var LOG_VERSION;
|
|
@@ -488,6 +575,7 @@ async function runAgentTurn(opts2) {
|
|
|
488
575
|
let lastUsage = null;
|
|
489
576
|
for (let iter = 0; iter < max; iter++) {
|
|
490
577
|
turn++;
|
|
578
|
+
const previousMessages = opts2.messages.slice();
|
|
491
579
|
const toolCalls = [];
|
|
492
580
|
const toolResults = [];
|
|
493
581
|
let content = "";
|
|
@@ -502,7 +590,8 @@ async function runAgentTurn(opts2) {
|
|
|
502
590
|
signal: opts2.signal,
|
|
503
591
|
temperature: opts2.temperature,
|
|
504
592
|
maxCompletionTokens: opts2.maxCompletionTokens,
|
|
505
|
-
reasoningEffort: opts2.reasoningEffort
|
|
593
|
+
reasoningEffort: opts2.reasoningEffort,
|
|
594
|
+
sessionId: opts2.sessionId
|
|
506
595
|
});
|
|
507
596
|
for await (const ev of events) {
|
|
508
597
|
switch (ev.type) {
|
|
@@ -561,6 +650,7 @@ async function runAgentTurn(opts2) {
|
|
|
561
650
|
sessionId: opts2.sessionId,
|
|
562
651
|
turn,
|
|
563
652
|
messages: opts2.messages,
|
|
653
|
+
previousMessages,
|
|
564
654
|
toolResults,
|
|
565
655
|
usage: lastUsage
|
|
566
656
|
});
|
|
@@ -588,6 +678,7 @@ async function runAgentTurn(opts2) {
|
|
|
588
678
|
sessionId: opts2.sessionId,
|
|
589
679
|
turn,
|
|
590
680
|
messages: opts2.messages,
|
|
681
|
+
previousMessages,
|
|
591
682
|
toolResults,
|
|
592
683
|
usage: lastUsage
|
|
593
684
|
});
|
|
@@ -847,25 +938,8 @@ function loadContextFile(cwd) {
|
|
|
847
938
|
}
|
|
848
939
|
return null;
|
|
849
940
|
}
|
|
850
|
-
function
|
|
851
|
-
|
|
852
|
-
const date = now2.toISOString().slice(0, 10);
|
|
853
|
-
const shell = process.env.SHELL ? basename(process.env.SHELL) : "sh";
|
|
854
|
-
const toolsBlock = opts2.tools.map((t) => {
|
|
855
|
-
const perm = t.needsPermission ? " [needs user permission]" : "";
|
|
856
|
-
return `- \`${t.name}\`${perm}: ${t.description.split("\n")[0]}`;
|
|
857
|
-
}).join("\n");
|
|
858
|
-
const base = `You are kimiflare, an interactive coding assistant running in the user's terminal. You act on the user's local filesystem through the tools listed below. You are powered by the ${opts2.model} model on Cloudflare Workers AI.
|
|
859
|
-
|
|
860
|
-
Environment:
|
|
861
|
-
- Working directory: ${opts2.cwd}
|
|
862
|
-
- Platform: ${platform()} ${release()}
|
|
863
|
-
- Shell: ${shell}
|
|
864
|
-
- Home: ${homedir3()}
|
|
865
|
-
- Today: ${date}
|
|
866
|
-
|
|
867
|
-
Tools available:
|
|
868
|
-
${toolsBlock}
|
|
941
|
+
function buildStaticPrefix(opts2) {
|
|
942
|
+
return `You are kimiflare, an interactive coding assistant running in the user's terminal. You act on the user's local filesystem through the tools listed below. You are powered by the ${opts2.model} model on Cloudflare Workers AI.
|
|
869
943
|
|
|
870
944
|
How to work:
|
|
871
945
|
- Prefer calling tools over guessing. Read files before editing them. Use \`glob\` and \`grep\` to explore code before assuming structure.
|
|
@@ -878,13 +952,39 @@ How to work:
|
|
|
878
952
|
- If a request is ambiguous, ask one focused question instead of making large assumptions.
|
|
879
953
|
- When you finish a task, stop. Do not add a closing summary.
|
|
880
954
|
- When creating git commits, you must include \`Co-authored-by: kimiflare <kimiflare@proton.me>\` in the commit message so kimiflare is credited as a contributor. The bash tool will also auto-append this trailer when it detects git commit-creating commands.`;
|
|
955
|
+
}
|
|
956
|
+
function buildSessionPrefix(opts2) {
|
|
957
|
+
const now2 = opts2.now ?? /* @__PURE__ */ new Date();
|
|
958
|
+
const date = now2.toISOString().slice(0, 10);
|
|
959
|
+
const shell = process.env.SHELL ? basename(process.env.SHELL) : "sh";
|
|
960
|
+
const toolsBlock = opts2.tools.map((t) => {
|
|
961
|
+
const perm = t.needsPermission ? " [needs user permission]" : "";
|
|
962
|
+
return `- \`${t.name}\`${perm}: ${t.description.split("\n")[0]}`;
|
|
963
|
+
}).join("\n");
|
|
964
|
+
const env2 = `Environment:
|
|
965
|
+
- Working directory: ${opts2.cwd}
|
|
966
|
+
- Platform: ${platform()} ${release()}
|
|
967
|
+
- Shell: ${shell}
|
|
968
|
+
- Home: ${homedir3()}
|
|
969
|
+
- Today: ${date}`;
|
|
970
|
+
const tools = `Tools available:
|
|
971
|
+
${toolsBlock}`;
|
|
881
972
|
const ctx = loadContextFile(opts2.cwd);
|
|
882
973
|
const contextBlock = ctx ? `
|
|
883
974
|
|
|
884
975
|
Project context from ${ctx.name} (${ctx.lineCount} lines, treat as authoritative):
|
|
885
976
|
${ctx.content.trim()}` : "";
|
|
886
977
|
const modeBlock = opts2.mode ? systemPromptForMode(opts2.mode) : "";
|
|
887
|
-
return
|
|
978
|
+
return env2 + "\n\n" + tools + contextBlock + modeBlock;
|
|
979
|
+
}
|
|
980
|
+
function buildSystemPrompt(opts2) {
|
|
981
|
+
return buildStaticPrefix(opts2) + "\n\n" + buildSessionPrefix(opts2);
|
|
982
|
+
}
|
|
983
|
+
function buildSystemMessages(opts2) {
|
|
984
|
+
return [
|
|
985
|
+
{ role: "system", content: buildStaticPrefix(opts2) },
|
|
986
|
+
{ role: "system", content: buildSessionPrefix(opts2) }
|
|
987
|
+
];
|
|
888
988
|
}
|
|
889
989
|
var CONTEXT_FILENAMES, MAX_CONTEXT_BYTES;
|
|
890
990
|
var init_system_prompt = __esm({
|
|
@@ -1712,11 +1812,15 @@ function indexOfNthUserFromEnd(messages, n) {
|
|
|
1712
1812
|
async function compactMessages(opts2) {
|
|
1713
1813
|
const keep = opts2.keepLastTurns ?? 4;
|
|
1714
1814
|
const messages = opts2.messages;
|
|
1715
|
-
|
|
1716
|
-
|
|
1815
|
+
let prefixEnd = 0;
|
|
1816
|
+
while (prefixEnd < messages.length && messages[prefixEnd].role === "system") {
|
|
1817
|
+
prefixEnd++;
|
|
1818
|
+
}
|
|
1819
|
+
const prefix = messages.slice(0, prefixEnd);
|
|
1820
|
+
if (prefix.length === 0) throw new Error("compact: no system message found");
|
|
1717
1821
|
const cutoffUserIdx = indexOfNthUserFromEnd(messages, keep);
|
|
1718
1822
|
const firstKeepIdx = cutoffUserIdx >= 0 ? cutoffUserIdx : messages.length;
|
|
1719
|
-
const toSummarize = messages.slice(
|
|
1823
|
+
const toSummarize = messages.slice(prefixEnd, firstKeepIdx);
|
|
1720
1824
|
const toKeep = messages.slice(firstKeepIdx);
|
|
1721
1825
|
if (toSummarize.length === 0) {
|
|
1722
1826
|
return { summary: "", newMessages: messages, replacedCount: 0 };
|
|
@@ -1758,7 +1862,7 @@ ${summary.trim()}`
|
|
|
1758
1862
|
};
|
|
1759
1863
|
return {
|
|
1760
1864
|
summary: summary.trim(),
|
|
1761
|
-
newMessages: [
|
|
1865
|
+
newMessages: [...prefix, summaryMsg, ...toKeep],
|
|
1762
1866
|
replacedCount: toSummarize.length
|
|
1763
1867
|
};
|
|
1764
1868
|
}
|
|
@@ -3970,6 +4074,17 @@ function capEvents(prev) {
|
|
|
3970
4074
|
if (prev.length <= MAX_EVENTS) return prev;
|
|
3971
4075
|
return prev.slice(prev.length - MAX_EVENTS);
|
|
3972
4076
|
}
|
|
4077
|
+
function makePrefixMessages(cacheStable, model, mode, tools) {
|
|
4078
|
+
if (cacheStable) {
|
|
4079
|
+
return buildSystemMessages({ cwd: process.cwd(), tools, model, mode });
|
|
4080
|
+
}
|
|
4081
|
+
return [
|
|
4082
|
+
{
|
|
4083
|
+
role: "system",
|
|
4084
|
+
content: buildSystemPrompt({ cwd: process.cwd(), tools, model, mode })
|
|
4085
|
+
}
|
|
4086
|
+
];
|
|
4087
|
+
}
|
|
3973
4088
|
function findImagePaths(text) {
|
|
3974
4089
|
const paths = [];
|
|
3975
4090
|
for (const token of text.split(/\s+/)) {
|
|
@@ -4017,17 +4132,10 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4017
4132
|
const [verbose, setVerbose] = useState6(false);
|
|
4018
4133
|
const [hasUpdate, setHasUpdate] = useState6(initialUpdateResult?.hasUpdate ?? false);
|
|
4019
4134
|
const [latestVersion, setLatestVersion] = useState6(initialUpdateResult?.latestVersion ?? null);
|
|
4020
|
-
const
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
cwd: process.cwd(),
|
|
4025
|
-
tools: ALL_TOOLS,
|
|
4026
|
-
model: cfg?.model ?? DEFAULT_MODEL,
|
|
4027
|
-
mode: "edit"
|
|
4028
|
-
})
|
|
4029
|
-
}
|
|
4030
|
-
]);
|
|
4135
|
+
const cacheStableRef = useRef3(initialCfg?.cacheStablePrompts !== false);
|
|
4136
|
+
const messagesRef = useRef3(
|
|
4137
|
+
makePrefixMessages(cacheStableRef.current, cfg?.model ?? DEFAULT_MODEL, "edit", ALL_TOOLS)
|
|
4138
|
+
);
|
|
4031
4139
|
const executorRef = useRef3(new ToolExecutor(ALL_TOOLS));
|
|
4032
4140
|
const activeAsstIdRef = useRef3(null);
|
|
4033
4141
|
const activeControllerRef = useRef3(null);
|
|
@@ -4095,15 +4203,27 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4095
4203
|
}, [cfg, initialUpdateResult]);
|
|
4096
4204
|
useEffect4(() => {
|
|
4097
4205
|
modeRef.current = mode;
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4206
|
+
if (cacheStableRef.current) {
|
|
4207
|
+
messagesRef.current[1] = {
|
|
4208
|
+
role: "system",
|
|
4209
|
+
content: buildSessionPrefix({
|
|
4210
|
+
cwd: process.cwd(),
|
|
4211
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4212
|
+
model: cfg?.model ?? DEFAULT_MODEL,
|
|
4213
|
+
mode
|
|
4214
|
+
})
|
|
4215
|
+
};
|
|
4216
|
+
} else {
|
|
4217
|
+
messagesRef.current[0] = {
|
|
4218
|
+
role: "system",
|
|
4219
|
+
content: buildSystemPrompt({
|
|
4220
|
+
cwd: process.cwd(),
|
|
4221
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4222
|
+
model: cfg?.model ?? DEFAULT_MODEL,
|
|
4223
|
+
mode
|
|
4224
|
+
})
|
|
4225
|
+
};
|
|
4226
|
+
}
|
|
4107
4227
|
if (mode === "plan") {
|
|
4108
4228
|
executorRef.current.clearSessionPermissions();
|
|
4109
4229
|
}
|
|
@@ -4176,15 +4296,27 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4176
4296
|
}
|
|
4177
4297
|
}
|
|
4178
4298
|
if (totalTools > 0) {
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4299
|
+
if (cacheStableRef.current) {
|
|
4300
|
+
messagesRef.current[1] = {
|
|
4301
|
+
role: "system",
|
|
4302
|
+
content: buildSessionPrefix({
|
|
4303
|
+
cwd: process.cwd(),
|
|
4304
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4305
|
+
model: cfg.model ?? DEFAULT_MODEL,
|
|
4306
|
+
mode: modeRef.current
|
|
4307
|
+
})
|
|
4308
|
+
};
|
|
4309
|
+
} else {
|
|
4310
|
+
messagesRef.current[0] = {
|
|
4311
|
+
role: "system",
|
|
4312
|
+
content: buildSystemPrompt({
|
|
4313
|
+
cwd: process.cwd(),
|
|
4314
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4315
|
+
model: cfg.model ?? DEFAULT_MODEL,
|
|
4316
|
+
mode: modeRef.current
|
|
4317
|
+
})
|
|
4318
|
+
};
|
|
4319
|
+
}
|
|
4188
4320
|
setEvents((e) => [
|
|
4189
4321
|
...e,
|
|
4190
4322
|
{ kind: "info", key: mkKey(), text: `MCP connected \u2014 ${totalTools} external tool${totalTools === 1 ? "" : "s"} available` }
|
|
@@ -4457,15 +4589,27 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4457
4589
|
}
|
|
4458
4590
|
});
|
|
4459
4591
|
if (existsSync(join8(cwd, "KIMI.md"))) {
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4592
|
+
if (cacheStableRef.current) {
|
|
4593
|
+
messagesRef.current[1] = {
|
|
4594
|
+
role: "system",
|
|
4595
|
+
content: buildSessionPrefix({
|
|
4596
|
+
cwd,
|
|
4597
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4598
|
+
model: cfg.model,
|
|
4599
|
+
mode: modeRef.current
|
|
4600
|
+
})
|
|
4601
|
+
};
|
|
4602
|
+
} else {
|
|
4603
|
+
messagesRef.current[0] = {
|
|
4604
|
+
role: "system",
|
|
4605
|
+
content: buildSystemPrompt({
|
|
4606
|
+
cwd,
|
|
4607
|
+
tools: [...ALL_TOOLS, ...mcpToolsRef.current],
|
|
4608
|
+
model: cfg.model,
|
|
4609
|
+
mode: modeRef.current
|
|
4610
|
+
})
|
|
4611
|
+
};
|
|
4612
|
+
}
|
|
4469
4613
|
setEvents((e) => [
|
|
4470
4614
|
...e,
|
|
4471
4615
|
{ kind: "info", key: mkKey(), text: "KIMI.md generated; context loaded for future turns" }
|
|
@@ -4549,7 +4693,11 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4549
4693
|
return true;
|
|
4550
4694
|
}
|
|
4551
4695
|
if (c === "/clear") {
|
|
4552
|
-
|
|
4696
|
+
if (cacheStableRef.current && messagesRef.current.length >= 2) {
|
|
4697
|
+
messagesRef.current = [messagesRef.current[0], messagesRef.current[1]];
|
|
4698
|
+
} else {
|
|
4699
|
+
messagesRef.current = [messagesRef.current[0]];
|
|
4700
|
+
}
|
|
4553
4701
|
sessionIdRef.current = null;
|
|
4554
4702
|
setEvents([]);
|
|
4555
4703
|
setUsage(null);
|