kimiflare 0.9.0 → 0.9.2
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 +110 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -172,7 +172,7 @@ function isRetryable(err, attempt) {
|
|
|
172
172
|
async function* runKimi(opts2) {
|
|
173
173
|
const url = `https://api.cloudflare.com/client/v4/accounts/${opts2.accountId}/ai/run/${opts2.model}`;
|
|
174
174
|
const body = {
|
|
175
|
-
messages: opts2.messages,
|
|
175
|
+
messages: sanitizeMessagesForApi(opts2.messages),
|
|
176
176
|
...opts2.tools && opts2.tools.length ? { tools: opts2.tools, tool_choice: "auto", parallel_tool_calls: true } : {},
|
|
177
177
|
stream: true,
|
|
178
178
|
temperature: opts2.temperature ?? 0.2,
|
|
@@ -294,6 +294,30 @@ async function* parseStream(body, signal) {
|
|
|
294
294
|
}
|
|
295
295
|
yield { type: "done", finishReason, usage: lastUsage };
|
|
296
296
|
}
|
|
297
|
+
function sanitizeMessagesForApi(messages) {
|
|
298
|
+
return messages.map((m) => {
|
|
299
|
+
if (!m.tool_calls || m.tool_calls.length === 0) return m;
|
|
300
|
+
return {
|
|
301
|
+
...m,
|
|
302
|
+
tool_calls: m.tool_calls.map((tc) => ({
|
|
303
|
+
...tc,
|
|
304
|
+
function: {
|
|
305
|
+
name: tc.function.name,
|
|
306
|
+
arguments: validateJsonArguments(tc.function.arguments)
|
|
307
|
+
}
|
|
308
|
+
}))
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
function validateJsonArguments(raw) {
|
|
313
|
+
if (!raw || !raw.trim()) return "{}";
|
|
314
|
+
try {
|
|
315
|
+
JSON.parse(raw);
|
|
316
|
+
return raw;
|
|
317
|
+
} catch {
|
|
318
|
+
return "{}";
|
|
319
|
+
}
|
|
320
|
+
}
|
|
297
321
|
function extractCloudflareError(parsed) {
|
|
298
322
|
if (!parsed || typeof parsed !== "object") return null;
|
|
299
323
|
const cf = parsed;
|
|
@@ -387,10 +411,11 @@ async function runAgentTurn(opts2) {
|
|
|
387
411
|
opts2.callbacks.onToolCallArgs?.(ev.index, ev.argsDelta);
|
|
388
412
|
break;
|
|
389
413
|
case "tool_call_complete": {
|
|
414
|
+
const safeArgs = validateToolArguments(ev.arguments);
|
|
390
415
|
const call = {
|
|
391
416
|
id: ev.id,
|
|
392
417
|
type: "function",
|
|
393
|
-
function: { name: ev.name, arguments:
|
|
418
|
+
function: { name: ev.name, arguments: safeArgs }
|
|
394
419
|
};
|
|
395
420
|
toolCalls.push(call);
|
|
396
421
|
opts2.callbacks.onToolCallFinalized?.(call);
|
|
@@ -438,6 +463,15 @@ async function runAgentTurn(opts2) {
|
|
|
438
463
|
}
|
|
439
464
|
throw new Error(`kimiflare: tool iteration limit reached (${opts2.maxToolIterations ?? 50})`);
|
|
440
465
|
}
|
|
466
|
+
function validateToolArguments(raw) {
|
|
467
|
+
if (!raw || !raw.trim()) return "{}";
|
|
468
|
+
try {
|
|
469
|
+
JSON.parse(raw);
|
|
470
|
+
return raw;
|
|
471
|
+
} catch {
|
|
472
|
+
return "{}";
|
|
473
|
+
}
|
|
474
|
+
}
|
|
441
475
|
var init_loop = __esm({
|
|
442
476
|
"src/agent/loop.ts"() {
|
|
443
477
|
"use strict";
|
|
@@ -1474,10 +1508,11 @@ var init_tool_view = __esm({
|
|
|
1474
1508
|
});
|
|
1475
1509
|
|
|
1476
1510
|
// src/ui/markdown.tsx
|
|
1511
|
+
import { useMemo } from "react";
|
|
1477
1512
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
1478
1513
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1479
1514
|
function MD({ text, theme }) {
|
|
1480
|
-
const blocks = parseBlocks(text);
|
|
1515
|
+
const blocks = useMemo(() => parseBlocks(text), [text]);
|
|
1481
1516
|
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: blocks.map((b, i) => /* @__PURE__ */ jsx3(Block, { block: b, theme }, i)) });
|
|
1482
1517
|
}
|
|
1483
1518
|
function parseBlocks(src) {
|
|
@@ -1633,19 +1668,10 @@ var init_markdown = __esm({
|
|
|
1633
1668
|
});
|
|
1634
1669
|
|
|
1635
1670
|
// src/ui/chat.tsx
|
|
1671
|
+
import React2 from "react";
|
|
1636
1672
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
1637
1673
|
import Spinner2 from "ink-spinner";
|
|
1638
1674
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1639
|
-
function ChatView({ events, showReasoning, theme, verbose }) {
|
|
1640
|
-
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: events.map((e, i) => {
|
|
1641
|
-
const prev = events[i - 1];
|
|
1642
|
-
const showSeparator = e.kind === "user" && prev && (prev.kind === "assistant" || prev.kind === "tool");
|
|
1643
|
-
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
1644
|
-
showSeparator && /* @__PURE__ */ jsx4(Box4, { marginY: 1, children: /* @__PURE__ */ jsx4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: "\u2500".repeat(40) }) }),
|
|
1645
|
-
/* @__PURE__ */ jsx4(EventView, { evt: e, showReasoning, theme, verbose })
|
|
1646
|
-
] }, e.key);
|
|
1647
|
-
}) });
|
|
1648
|
-
}
|
|
1649
1675
|
function EventView({
|
|
1650
1676
|
evt,
|
|
1651
1677
|
showReasoning,
|
|
@@ -1686,11 +1712,22 @@ function EventView({
|
|
|
1686
1712
|
evt.text
|
|
1687
1713
|
] });
|
|
1688
1714
|
}
|
|
1715
|
+
var ChatView;
|
|
1689
1716
|
var init_chat = __esm({
|
|
1690
1717
|
"src/ui/chat.tsx"() {
|
|
1691
1718
|
"use strict";
|
|
1692
1719
|
init_tool_view();
|
|
1693
1720
|
init_markdown();
|
|
1721
|
+
ChatView = React2.memo(function ChatView2({ events, showReasoning, theme, verbose }) {
|
|
1722
|
+
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: events.map((e, i) => {
|
|
1723
|
+
const prev = events[i - 1];
|
|
1724
|
+
const showSeparator = e.kind === "user" && prev && (prev.kind === "assistant" || prev.kind === "tool");
|
|
1725
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
1726
|
+
showSeparator && /* @__PURE__ */ jsx4(Box4, { marginY: 1, children: /* @__PURE__ */ jsx4(Text4, { color: theme.info.color, dimColor: theme.info.dim, children: "\u2500".repeat(40) }) }),
|
|
1727
|
+
/* @__PURE__ */ jsx4(EventView, { evt: e, showReasoning, theme, verbose })
|
|
1728
|
+
] }, e.key);
|
|
1729
|
+
}) });
|
|
1730
|
+
});
|
|
1694
1731
|
}
|
|
1695
1732
|
});
|
|
1696
1733
|
|
|
@@ -1943,19 +1980,25 @@ var init_theme_picker = __esm({
|
|
|
1943
1980
|
});
|
|
1944
1981
|
|
|
1945
1982
|
// src/ui/task-list.tsx
|
|
1946
|
-
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
1983
|
+
import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
1947
1984
|
import { Box as Box9, Text as Text9 } from "ink";
|
|
1948
1985
|
import Spinner4 from "ink-spinner";
|
|
1949
1986
|
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1950
1987
|
function TaskList({ tasks, theme, startedAt, tokensDelta }) {
|
|
1951
1988
|
const [now, setNow] = useState3(Date.now());
|
|
1989
|
+
const tasksRef = useRef(tasks);
|
|
1990
|
+
tasksRef.current = tasks;
|
|
1952
1991
|
useEffect2(() => {
|
|
1953
1992
|
if (startedAt === null) return;
|
|
1954
|
-
const
|
|
1955
|
-
|
|
1956
|
-
|
|
1993
|
+
const id = setInterval(() => {
|
|
1994
|
+
setNow(Date.now());
|
|
1995
|
+
const current = tasksRef.current;
|
|
1996
|
+
if (current.length > 0 && current.every((t) => t.status === "completed")) {
|
|
1997
|
+
clearInterval(id);
|
|
1998
|
+
}
|
|
1999
|
+
}, 1e3);
|
|
1957
2000
|
return () => clearInterval(id);
|
|
1958
|
-
}, [startedAt
|
|
2001
|
+
}, [startedAt]);
|
|
1959
2002
|
if (tasks.length === 0) return null;
|
|
1960
2003
|
const active = tasks.find((t) => t.status === "in_progress");
|
|
1961
2004
|
const done = tasks.filter((t) => t.status === "completed").length;
|
|
@@ -2547,7 +2590,7 @@ var init_source = __esm({
|
|
|
2547
2590
|
});
|
|
2548
2591
|
|
|
2549
2592
|
// src/ui/text-input.tsx
|
|
2550
|
-
import { useState as useState4, useEffect as useEffect3, useRef } from "react";
|
|
2593
|
+
import { useState as useState4, useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
2551
2594
|
import { Text as Text10, useInput } from "ink";
|
|
2552
2595
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2553
2596
|
function shouldTreatAsPaste(input) {
|
|
@@ -2583,7 +2626,7 @@ function CustomTextInput({
|
|
|
2583
2626
|
enablePaste = false
|
|
2584
2627
|
}) {
|
|
2585
2628
|
const [cursorOffset, setCursorOffset] = useState4(value.length);
|
|
2586
|
-
const pastesRef =
|
|
2629
|
+
const pastesRef = useRef2(/* @__PURE__ */ new Map());
|
|
2587
2630
|
useEffect3(() => {
|
|
2588
2631
|
if (!focus) return;
|
|
2589
2632
|
setCursorOffset((prev) => prev > value.length ? value.length : prev);
|
|
@@ -3269,16 +3312,29 @@ var app_exports = {};
|
|
|
3269
3312
|
__export(app_exports, {
|
|
3270
3313
|
renderApp: () => renderApp
|
|
3271
3314
|
});
|
|
3272
|
-
import { useState as useState6, useRef as
|
|
3315
|
+
import { useState as useState6, useRef as useRef3, useEffect as useEffect4, useCallback } from "react";
|
|
3273
3316
|
import { Box as Box12, Text as Text13, useApp, useInput as useInput2, render } from "ink";
|
|
3274
3317
|
import { existsSync } from "fs";
|
|
3275
3318
|
import { join as join5 } from "path";
|
|
3276
3319
|
import { unlink } from "fs/promises";
|
|
3277
3320
|
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3321
|
+
function capEvents(prev) {
|
|
3322
|
+
if (prev.length <= MAX_EVENTS) return prev;
|
|
3323
|
+
return prev.slice(prev.length - MAX_EVENTS);
|
|
3324
|
+
}
|
|
3278
3325
|
function App({ initialCfg, initialUpdateResult }) {
|
|
3279
3326
|
const { exit } = useApp();
|
|
3280
3327
|
const [cfg, setCfg] = useState6(initialCfg);
|
|
3281
|
-
const [events,
|
|
3328
|
+
const [events, setRawEvents] = useState6([]);
|
|
3329
|
+
const setEvents = useCallback(
|
|
3330
|
+
(updater) => {
|
|
3331
|
+
setRawEvents((prev) => {
|
|
3332
|
+
const next = typeof updater === "function" ? updater(prev) : updater;
|
|
3333
|
+
return capEvents(next);
|
|
3334
|
+
});
|
|
3335
|
+
},
|
|
3336
|
+
[]
|
|
3337
|
+
);
|
|
3282
3338
|
const [input, setInput] = useState6("");
|
|
3283
3339
|
const [busy, setBusy] = useState6(false);
|
|
3284
3340
|
const [usage, setUsage] = useState6(null);
|
|
@@ -3303,7 +3359,7 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3303
3359
|
const [verbose, setVerbose] = useState6(false);
|
|
3304
3360
|
const [hasUpdate, setHasUpdate] = useState6(initialUpdateResult?.hasUpdate ?? false);
|
|
3305
3361
|
const [latestVersion, setLatestVersion] = useState6(initialUpdateResult?.latestVersion ?? null);
|
|
3306
|
-
const messagesRef =
|
|
3362
|
+
const messagesRef = useRef3([
|
|
3307
3363
|
{
|
|
3308
3364
|
role: "system",
|
|
3309
3365
|
content: buildSystemPrompt({
|
|
@@ -3314,17 +3370,17 @@ function App({ initialCfg, initialUpdateResult }) {
|
|
|
3314
3370
|
})
|
|
3315
3371
|
}
|
|
3316
3372
|
]);
|
|
3317
|
-
const executorRef =
|
|
3318
|
-
const activeAsstIdRef =
|
|
3319
|
-
const activeControllerRef =
|
|
3320
|
-
const sessionIdRef =
|
|
3321
|
-
const modeRef =
|
|
3322
|
-
const effortRef =
|
|
3323
|
-
const tasksRef =
|
|
3324
|
-
const usageRef =
|
|
3325
|
-
const updateCheckedRef =
|
|
3326
|
-
const updateNudgedRef =
|
|
3327
|
-
const compactSuggestedRef =
|
|
3373
|
+
const executorRef = useRef3(new ToolExecutor(ALL_TOOLS));
|
|
3374
|
+
const activeAsstIdRef = useRef3(null);
|
|
3375
|
+
const activeControllerRef = useRef3(null);
|
|
3376
|
+
const sessionIdRef = useRef3(null);
|
|
3377
|
+
const modeRef = useRef3(mode);
|
|
3378
|
+
const effortRef = useRef3(effort);
|
|
3379
|
+
const tasksRef = useRef3([]);
|
|
3380
|
+
const usageRef = useRef3(null);
|
|
3381
|
+
const updateCheckedRef = useRef3(false);
|
|
3382
|
+
const updateNudgedRef = useRef3(false);
|
|
3383
|
+
const compactSuggestedRef = useRef3(false);
|
|
3328
3384
|
useEffect4(() => {
|
|
3329
3385
|
if (!cfg || updateCheckedRef.current) return;
|
|
3330
3386
|
updateCheckedRef.current = true;
|
|
@@ -4070,10 +4126,23 @@ use: /thinking low | medium | high`
|
|
|
4070
4126
|
if (e.name === "AbortError") {
|
|
4071
4127
|
setEvents((es) => [...es, { kind: "info", key: mkKey(), text: "(aborted)" }]);
|
|
4072
4128
|
} else {
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4129
|
+
const isInvalidJson400 = e instanceof KimiApiError && e.httpStatus === 400 && e.message.includes("invalid escaped character");
|
|
4130
|
+
if (isInvalidJson400) {
|
|
4131
|
+
messagesRef.current.pop();
|
|
4132
|
+
setEvents((es) => [
|
|
4133
|
+
...es,
|
|
4134
|
+
{
|
|
4135
|
+
kind: "error",
|
|
4136
|
+
key: mkKey(),
|
|
4137
|
+
text: "API rejected request (invalid JSON in conversation history). Retrying may work; run /clear to reset if it persists."
|
|
4138
|
+
}
|
|
4139
|
+
]);
|
|
4140
|
+
} else {
|
|
4141
|
+
setEvents((es) => [
|
|
4142
|
+
...es,
|
|
4143
|
+
{ kind: "error", key: mkKey(), text: e.message ?? String(e) }
|
|
4144
|
+
]);
|
|
4145
|
+
}
|
|
4077
4146
|
}
|
|
4078
4147
|
} finally {
|
|
4079
4148
|
setBusy(false);
|
|
@@ -4242,7 +4311,7 @@ async function renderApp(cfg, updateResult) {
|
|
|
4242
4311
|
const instance = render(/* @__PURE__ */ jsx13(App, { initialCfg: cfg, initialUpdateResult: updateResult }));
|
|
4243
4312
|
await instance.waitUntilExit();
|
|
4244
4313
|
}
|
|
4245
|
-
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, nextAssistantId, nextKey, mkKey, EFFORT_DESCRIPTIONS;
|
|
4314
|
+
var CONTEXT_LIMIT, AUTO_COMPACT_SUGGEST_PCT, MAX_EVENTS, nextAssistantId, nextKey, mkKey, EFFORT_DESCRIPTIONS;
|
|
4246
4315
|
var init_app = __esm({
|
|
4247
4316
|
"src/app.tsx"() {
|
|
4248
4317
|
"use strict";
|
|
@@ -4251,6 +4320,7 @@ var init_app = __esm({
|
|
|
4251
4320
|
init_compact();
|
|
4252
4321
|
init_executor();
|
|
4253
4322
|
init_messages();
|
|
4323
|
+
init_errors();
|
|
4254
4324
|
init_chat();
|
|
4255
4325
|
init_status();
|
|
4256
4326
|
init_permission();
|
|
@@ -4267,6 +4337,7 @@ var init_app = __esm({
|
|
|
4267
4337
|
init_sessions();
|
|
4268
4338
|
CONTEXT_LIMIT = 262e3;
|
|
4269
4339
|
AUTO_COMPACT_SUGGEST_PCT = 0.8;
|
|
4340
|
+
MAX_EVENTS = 500;
|
|
4270
4341
|
nextAssistantId = 1;
|
|
4271
4342
|
nextKey = 1;
|
|
4272
4343
|
mkKey = () => `evt_${nextKey++}`;
|