kimiflare 0.12.0 → 0.13.1
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 +179 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -230,57 +230,87 @@ async function* parseStream(body, signal) {
|
|
|
230
230
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
231
231
|
let lastUsage = null;
|
|
232
232
|
let finishReason = null;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
233
|
+
let timeoutId = null;
|
|
234
|
+
let timedOut = false;
|
|
235
|
+
const resetTimeout = () => {
|
|
236
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
237
|
+
timeoutId = setTimeout(() => {
|
|
238
|
+
timedOut = true;
|
|
239
|
+
}, STREAM_TIMEOUT_MS);
|
|
240
|
+
};
|
|
241
|
+
try {
|
|
242
|
+
for await (const dataStr of readSSE(body, signal)) {
|
|
243
|
+
if (timedOut) {
|
|
244
|
+
throw new KimiApiError(
|
|
245
|
+
`kimiflare: stream timed out (no data for ${STREAM_TIMEOUT_MS / 1e3}s)`,
|
|
246
|
+
void 0,
|
|
247
|
+
void 0
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
resetTimeout();
|
|
251
|
+
if (dataStr === "[DONE]") break;
|
|
252
|
+
let chunk = null;
|
|
253
|
+
try {
|
|
254
|
+
chunk = JSON.parse(dataStr);
|
|
255
|
+
} catch {
|
|
256
|
+
continue;
|
|
252
257
|
}
|
|
253
|
-
if (
|
|
254
|
-
|
|
258
|
+
if (!chunk) continue;
|
|
259
|
+
if (chunk.usage) {
|
|
260
|
+
lastUsage = chunk.usage;
|
|
261
|
+
yield { type: "usage", usage: chunk.usage };
|
|
255
262
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
263
|
+
const choice = chunk.choices?.[0];
|
|
264
|
+
if (!choice) continue;
|
|
265
|
+
const d = choice.delta;
|
|
266
|
+
if (d) {
|
|
267
|
+
if (typeof d.reasoning_content === "string" && d.reasoning_content.length) {
|
|
268
|
+
yield { type: "reasoning", delta: d.reasoning_content };
|
|
269
|
+
}
|
|
270
|
+
if (typeof d.content === "string" && d.content.length) {
|
|
271
|
+
yield { type: "text", delta: d.content };
|
|
272
|
+
}
|
|
273
|
+
if (Array.isArray(d.tool_calls)) {
|
|
274
|
+
for (const tc of d.tool_calls) {
|
|
275
|
+
const idx = typeof tc.index === "number" ? tc.index : 0;
|
|
276
|
+
let buf = toolCalls.get(idx);
|
|
277
|
+
const incomingName = tc.function?.name ?? null;
|
|
278
|
+
const incomingId = tc.id ?? null;
|
|
279
|
+
if (!buf) {
|
|
280
|
+
buf = { id: incomingId ?? `tc_${idx}`, name: incomingName ?? "", args: "" };
|
|
281
|
+
toolCalls.set(idx, buf);
|
|
282
|
+
if (buf.name) {
|
|
283
|
+
yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
if (!buf.name && incomingName) {
|
|
287
|
+
buf.name = incomingName;
|
|
288
|
+
yield { type: "tool_call_start", index: idx, id: buf.id, name: buf.name };
|
|
289
|
+
}
|
|
290
|
+
if (buf.id.startsWith("tc_") && incomingId) buf.id = incomingId;
|
|
267
291
|
}
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
buf.
|
|
271
|
-
yield { type: "
|
|
292
|
+
const argDelta = tc.function?.arguments;
|
|
293
|
+
if (typeof argDelta === "string" && argDelta.length) {
|
|
294
|
+
buf.args += argDelta;
|
|
295
|
+
yield { type: "tool_call_args", index: idx, argsDelta: argDelta };
|
|
272
296
|
}
|
|
273
|
-
if (buf.id.startsWith("tc_") && incomingId) buf.id = incomingId;
|
|
274
|
-
}
|
|
275
|
-
const argDelta = tc.function?.arguments;
|
|
276
|
-
if (typeof argDelta === "string" && argDelta.length) {
|
|
277
|
-
buf.args += argDelta;
|
|
278
|
-
yield { type: "tool_call_args", index: idx, argsDelta: argDelta };
|
|
279
297
|
}
|
|
280
298
|
}
|
|
281
299
|
}
|
|
300
|
+
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
282
301
|
}
|
|
283
|
-
|
|
302
|
+
for (const [idx, buf] of [...toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
|
|
303
|
+
if (!buf.name) continue;
|
|
304
|
+
yield {
|
|
305
|
+
type: "tool_call_complete",
|
|
306
|
+
index: idx,
|
|
307
|
+
id: buf.id,
|
|
308
|
+
name: buf.name,
|
|
309
|
+
arguments: buf.args
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
} finally {
|
|
313
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
284
314
|
}
|
|
285
315
|
for (const [idx, buf] of [...toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
|
|
286
316
|
if (!buf.name) continue;
|
|
@@ -354,7 +384,7 @@ function sleep(ms, signal) {
|
|
|
354
384
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
355
385
|
});
|
|
356
386
|
}
|
|
357
|
-
var RETRYABLE_CODES, MAX_ATTEMPTS;
|
|
387
|
+
var RETRYABLE_CODES, MAX_ATTEMPTS, STREAM_TIMEOUT_MS;
|
|
358
388
|
var init_client = __esm({
|
|
359
389
|
"src/agent/client.ts"() {
|
|
360
390
|
"use strict";
|
|
@@ -363,6 +393,7 @@ var init_client = __esm({
|
|
|
363
393
|
init_messages();
|
|
364
394
|
RETRYABLE_CODES = /* @__PURE__ */ new Set([3040]);
|
|
365
395
|
MAX_ATTEMPTS = 5;
|
|
396
|
+
STREAM_TIMEOUT_MS = 6e4;
|
|
366
397
|
}
|
|
367
398
|
});
|
|
368
399
|
|
|
@@ -3575,6 +3606,60 @@ function findImagePaths(text) {
|
|
|
3575
3606
|
}
|
|
3576
3607
|
return [...new Set(paths)];
|
|
3577
3608
|
}
|
|
3609
|
+
function stripImagesFromHistory(messages) {
|
|
3610
|
+
for (const m of messages) {
|
|
3611
|
+
if (!Array.isArray(m.content)) continue;
|
|
3612
|
+
let changed = false;
|
|
3613
|
+
const next = [];
|
|
3614
|
+
for (const part of m.content) {
|
|
3615
|
+
if (part.type === "image_url") {
|
|
3616
|
+
changed = true;
|
|
3617
|
+
next.push({ type: "text", text: "[image]" });
|
|
3618
|
+
} else {
|
|
3619
|
+
next.push(part);
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
if (changed) {
|
|
3623
|
+
m.content = next;
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
function truncateOldToolResults(messages, keepRecent) {
|
|
3628
|
+
const toolIndices = [];
|
|
3629
|
+
for (let i = 0; i < messages.length; i++) {
|
|
3630
|
+
if (messages[i].role === "tool") toolIndices.push(i);
|
|
3631
|
+
}
|
|
3632
|
+
const cutoff = toolIndices.length - keepRecent;
|
|
3633
|
+
for (let i = 0; i < cutoff; i++) {
|
|
3634
|
+
const idx = toolIndices[i];
|
|
3635
|
+
const m = messages[idx];
|
|
3636
|
+
const text = typeof m.content === "string" ? m.content : "";
|
|
3637
|
+
if (text.length > 500) {
|
|
3638
|
+
m.content = text.slice(0, 500) + "\n\u2026 [truncated]";
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
async function maybeAutoCompact(messages, cfg, onInfo) {
|
|
3643
|
+
const heapUsed = process.memoryUsage().heapUsed;
|
|
3644
|
+
if (heapUsed < HEAP_AUTO_COMPACT_THRESHOLD || messages.length <= MSG_AUTO_COMPACT_THRESHOLD) {
|
|
3645
|
+
return false;
|
|
3646
|
+
}
|
|
3647
|
+
onInfo("auto-compacting to reduce memory usage");
|
|
3648
|
+
const result = await compactMessages({
|
|
3649
|
+
accountId: cfg.accountId,
|
|
3650
|
+
apiToken: cfg.apiToken,
|
|
3651
|
+
model: cfg.model,
|
|
3652
|
+
messages,
|
|
3653
|
+
keepLastTurns: 2
|
|
3654
|
+
});
|
|
3655
|
+
if (result.replacedCount > 0) {
|
|
3656
|
+
messages.length = 0;
|
|
3657
|
+
messages.push(...result.newMessages);
|
|
3658
|
+
onInfo(`compacted ${result.replacedCount} messages into a summary`);
|
|
3659
|
+
return true;
|
|
3660
|
+
}
|
|
3661
|
+
return false;
|
|
3662
|
+
}
|
|
3578
3663
|
function App({ initialCfg, initialUpdateResult }) {
|
|
3579
3664
|
const { exit } = useApp();
|
|
3580
3665
|
const [cfg, setCfg] = useState6(initialCfg);
|
|
@@ -3626,6 +3711,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3626
3711
|
const executorRef = useRef3(new ToolExecutor(ALL_TOOLS));
|
|
3627
3712
|
const activeAsstIdRef = useRef3(null);
|
|
3628
3713
|
const activeControllerRef = useRef3(null);
|
|
3714
|
+
const permResolveRef = useRef3(null);
|
|
3629
3715
|
const sessionIdRef = useRef3(null);
|
|
3630
3716
|
const modeRef = useRef3(mode);
|
|
3631
3717
|
const effortRef = useRef3(effort);
|
|
@@ -3767,8 +3853,11 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3767
3853
|
}, [cfg]);
|
|
3768
3854
|
useInput2((inputChar, key) => {
|
|
3769
3855
|
if (key.ctrl && inputChar === "c") {
|
|
3770
|
-
if (busy
|
|
3771
|
-
activeControllerRef.current
|
|
3856
|
+
if (busy) {
|
|
3857
|
+
activeControllerRef.current?.abort();
|
|
3858
|
+
permResolveRef.current?.("deny");
|
|
3859
|
+
permResolveRef.current = null;
|
|
3860
|
+
setPerm(null);
|
|
3772
3861
|
setQueue([]);
|
|
3773
3862
|
setEvents((e) => [...e, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
|
|
3774
3863
|
} else {
|
|
@@ -3990,10 +4079,21 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3990
4079
|
resolve2("deny");
|
|
3991
4080
|
return;
|
|
3992
4081
|
}
|
|
3993
|
-
|
|
4082
|
+
permResolveRef.current = resolve2;
|
|
4083
|
+
setPerm({ tool: req.tool, args: req.args, resolve: (d) => {
|
|
4084
|
+
permResolveRef.current = null;
|
|
4085
|
+
resolve2(d);
|
|
4086
|
+
} });
|
|
3994
4087
|
})
|
|
3995
4088
|
}
|
|
3996
4089
|
});
|
|
4090
|
+
stripImagesFromHistory(messagesRef.current);
|
|
4091
|
+
truncateOldToolResults(messagesRef.current, 8);
|
|
4092
|
+
await maybeAutoCompact(
|
|
4093
|
+
messagesRef.current,
|
|
4094
|
+
cfg,
|
|
4095
|
+
(text) => setEvents((es) => [...es, { kind: "info", key: mkKey(), text }])
|
|
4096
|
+
);
|
|
3997
4097
|
if (existsSync(join5(cwd, "KIMI.md"))) {
|
|
3998
4098
|
messagesRef.current[0] = {
|
|
3999
4099
|
role: "system",
|
|
@@ -4010,17 +4110,25 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
4010
4110
|
]);
|
|
4011
4111
|
}
|
|
4012
4112
|
} catch (e) {
|
|
4013
|
-
if (e.name
|
|
4113
|
+
if (e.name === "AbortError") {
|
|
4114
|
+
setEvents((es) => [...es, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
|
|
4115
|
+
setEvents(
|
|
4116
|
+
(evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(interrupted)" } : e2)
|
|
4117
|
+
);
|
|
4118
|
+
} else {
|
|
4014
4119
|
setEvents((es) => [
|
|
4015
4120
|
...es,
|
|
4016
4121
|
{ kind: "error", key: mkKey(), text: `init failed: ${e.message}` }
|
|
4017
4122
|
]);
|
|
4018
4123
|
}
|
|
4019
4124
|
} finally {
|
|
4125
|
+
const asstId = activeAsstIdRef.current;
|
|
4126
|
+
if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
|
|
4020
4127
|
setBusy(false);
|
|
4021
4128
|
setTurnStartedAt(null);
|
|
4022
4129
|
activeAsstIdRef.current = null;
|
|
4023
4130
|
activeControllerRef.current = null;
|
|
4131
|
+
permResolveRef.current = null;
|
|
4024
4132
|
}
|
|
4025
4133
|
}, [cfg, busy, updateAssistant, updateTool]);
|
|
4026
4134
|
const handleResumePick = useCallback(
|
|
@@ -4432,14 +4540,28 @@ use: /thinking low | medium | high`
|
|
|
4432
4540
|
resolve2("deny");
|
|
4433
4541
|
return;
|
|
4434
4542
|
}
|
|
4435
|
-
|
|
4543
|
+
permResolveRef.current = resolve2;
|
|
4544
|
+
setPerm({ tool: req.tool, args: req.args, resolve: (d) => {
|
|
4545
|
+
permResolveRef.current = null;
|
|
4546
|
+
resolve2(d);
|
|
4547
|
+
} });
|
|
4436
4548
|
})
|
|
4437
4549
|
}
|
|
4438
4550
|
});
|
|
4439
|
-
|
|
4551
|
+
stripImagesFromHistory(messagesRef.current);
|
|
4552
|
+
truncateOldToolResults(messagesRef.current, 8);
|
|
4553
|
+
await maybeAutoCompact(
|
|
4554
|
+
messagesRef.current,
|
|
4555
|
+
cfg,
|
|
4556
|
+
(text2) => setEvents((es) => [...es, { kind: "info", key: mkKey(), text: text2 }])
|
|
4557
|
+
);
|
|
4558
|
+
void saveSessionSafe();
|
|
4440
4559
|
} catch (e) {
|
|
4441
4560
|
if (e.name === "AbortError") {
|
|
4442
|
-
setEvents((es) => [...es, { kind: "info", key: mkKey(), text: "(
|
|
4561
|
+
setEvents((es) => [...es, { kind: "info", key: mkKey(), text: "(interrupted)" }]);
|
|
4562
|
+
setEvents(
|
|
4563
|
+
(evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(interrupted)" } : e2)
|
|
4564
|
+
);
|
|
4443
4565
|
} else {
|
|
4444
4566
|
const isInvalidJson400 = e instanceof KimiApiError && e.httpStatus === 400 && e.message.includes("invalid escaped character");
|
|
4445
4567
|
if (isInvalidJson400) {
|
|
@@ -4460,10 +4582,13 @@ use: /thinking low | medium | high`
|
|
|
4460
4582
|
}
|
|
4461
4583
|
}
|
|
4462
4584
|
} finally {
|
|
4585
|
+
const asstId = activeAsstIdRef.current;
|
|
4586
|
+
if (asstId !== null) updateAssistant(asstId, () => ({ streaming: false }));
|
|
4463
4587
|
setBusy(false);
|
|
4464
4588
|
setTurnStartedAt(null);
|
|
4465
4589
|
activeAsstIdRef.current = null;
|
|
4466
4590
|
activeControllerRef.current = null;
|
|
4591
|
+
permResolveRef.current = null;
|
|
4467
4592
|
}
|
|
4468
4593
|
},
|
|
4469
4594
|
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe]
|
|
@@ -4626,7 +4751,7 @@ async function renderApp(cfg, updateResult) {
|
|
|
4626
4751
|
const instance = render(/* @__PURE__ */ jsx13(App, { initialCfg: cfg, initialUpdateResult: updateResult }));
|
|
4627
4752
|
await instance.waitUntilExit();
|
|
4628
4753
|
}
|
|
4629
|
-
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, MAX_EVENTS, nextAssistantId, nextKey, mkKey, MAX_IMAGES_PER_MESSAGE, EFFORT_DESCRIPTIONS;
|
|
4754
|
+
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, MAX_EVENTS, nextAssistantId, nextKey, mkKey, MAX_IMAGES_PER_MESSAGE, EFFORT_DESCRIPTIONS, HEAP_AUTO_COMPACT_THRESHOLD, MSG_AUTO_COMPACT_THRESHOLD;
|
|
4630
4755
|
var init_app = __esm({
|
|
4631
4756
|
"src/app.tsx"() {
|
|
4632
4757
|
"use strict";
|
|
@@ -4663,6 +4788,8 @@ var init_app = __esm({
|
|
|
4663
4788
|
medium: "medium \u2014 balanced (default). Solid quality on most edits, fast on trivial prompts.",
|
|
4664
4789
|
high: "high \u2014 deepest reasoning; slowest. Best for complex debugging, architecture, multi-file refactors."
|
|
4665
4790
|
};
|
|
4791
|
+
HEAP_AUTO_COMPACT_THRESHOLD = 2e9;
|
|
4792
|
+
MSG_AUTO_COMPACT_THRESHOLD = 50;
|
|
4666
4793
|
}
|
|
4667
4794
|
});
|
|
4668
4795
|
|