kimiflare 0.88.2 → 0.88.4
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 +1227 -915
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +14 -0
- package/dist/sdk/index.js +334 -90
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1363,6 +1363,562 @@ var init_messages = __esm({
|
|
|
1363
1363
|
}
|
|
1364
1364
|
});
|
|
1365
1365
|
|
|
1366
|
+
// src/agent/session-state.ts
|
|
1367
|
+
function emptySessionState(task = "") {
|
|
1368
|
+
return {
|
|
1369
|
+
task,
|
|
1370
|
+
user_constraints: [],
|
|
1371
|
+
repo_facts: [],
|
|
1372
|
+
files_touched: [],
|
|
1373
|
+
files_modified: [],
|
|
1374
|
+
confirmed_findings: [],
|
|
1375
|
+
open_questions: [],
|
|
1376
|
+
recent_failures: [],
|
|
1377
|
+
decisions: [],
|
|
1378
|
+
next_actions: [],
|
|
1379
|
+
artifact_index: {}
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
function serializeArtifactStore(store) {
|
|
1383
|
+
const MAX_ARTIFACT_CHARS = 5e4;
|
|
1384
|
+
const out = [];
|
|
1385
|
+
for (const a of store.list()) {
|
|
1386
|
+
out.push({
|
|
1387
|
+
id: a.id,
|
|
1388
|
+
type: a.type,
|
|
1389
|
+
summary: a.summary,
|
|
1390
|
+
raw: a.raw.slice(0, MAX_ARTIFACT_CHARS),
|
|
1391
|
+
source: a.source,
|
|
1392
|
+
path: a.path,
|
|
1393
|
+
lineRange: a.lineRange,
|
|
1394
|
+
ts: a.ts
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
return out;
|
|
1398
|
+
}
|
|
1399
|
+
function deserializeArtifactStore(data) {
|
|
1400
|
+
const store = new ArtifactStore();
|
|
1401
|
+
for (const a of data) {
|
|
1402
|
+
store.add({
|
|
1403
|
+
id: a.id,
|
|
1404
|
+
type: a.type,
|
|
1405
|
+
summary: a.summary,
|
|
1406
|
+
raw: a.raw,
|
|
1407
|
+
source: a.source,
|
|
1408
|
+
path: a.path,
|
|
1409
|
+
lineRange: a.lineRange,
|
|
1410
|
+
ts: a.ts
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
return store;
|
|
1414
|
+
}
|
|
1415
|
+
function formatRecalledArtifacts(recalled) {
|
|
1416
|
+
if (recalled.length === 0) return "";
|
|
1417
|
+
const lines = ["[recalled artifacts]"];
|
|
1418
|
+
for (const { id, artifact } of recalled) {
|
|
1419
|
+
lines.push(`--- artifact:${id} (${artifact.type} from ${artifact.source}) ---`);
|
|
1420
|
+
lines.push(artifact.raw);
|
|
1421
|
+
}
|
|
1422
|
+
return lines.join("\n");
|
|
1423
|
+
}
|
|
1424
|
+
function serializeSessionState(state) {
|
|
1425
|
+
const lines = [];
|
|
1426
|
+
lines.push(`task: ${state.task || "(none)"}`);
|
|
1427
|
+
if (state.user_constraints.length) lines.push(`constraints:
|
|
1428
|
+
${state.user_constraints.map((c) => " - " + c).join("\n")}`);
|
|
1429
|
+
if (state.repo_facts.length) lines.push(`repo_facts:
|
|
1430
|
+
${state.repo_facts.map((f) => " - " + f).join("\n")}`);
|
|
1431
|
+
if (state.files_touched.length) lines.push(`files_touched: ${state.files_touched.join(", ")}`);
|
|
1432
|
+
if (state.files_modified.length) lines.push(`files_modified: ${state.files_modified.join(", ")}`);
|
|
1433
|
+
if (state.confirmed_findings.length) lines.push(`findings:
|
|
1434
|
+
${state.confirmed_findings.map((f) => " - " + f).join("\n")}`);
|
|
1435
|
+
if (state.open_questions.length) lines.push(`open_questions:
|
|
1436
|
+
${state.open_questions.map((q) => " - " + q).join("\n")}`);
|
|
1437
|
+
if (state.recent_failures.length) lines.push(`recent_failures:
|
|
1438
|
+
${state.recent_failures.map((f) => " - " + f).join("\n")}`);
|
|
1439
|
+
if (state.decisions.length) lines.push(`decisions:
|
|
1440
|
+
${state.decisions.map((d) => " - " + d).join("\n")}`);
|
|
1441
|
+
if (state.next_actions.length) lines.push(`next_actions:
|
|
1442
|
+
${state.next_actions.map((a) => " - " + a).join("\n")}`);
|
|
1443
|
+
if (Object.keys(state.artifact_index).length) {
|
|
1444
|
+
lines.push("artifact_index:");
|
|
1445
|
+
for (const [id, meta] of Object.entries(state.artifact_index)) {
|
|
1446
|
+
lines.push(` ${id}: [${meta.type}] ${meta.summary}`);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return lines.join("\n");
|
|
1450
|
+
}
|
|
1451
|
+
function buildSessionStateMessage(state) {
|
|
1452
|
+
return {
|
|
1453
|
+
role: "system",
|
|
1454
|
+
content: `[compiled session state]
|
|
1455
|
+
${serializeSessionState(state)}`
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
var ArtifactStore;
|
|
1459
|
+
var init_session_state = __esm({
|
|
1460
|
+
"src/agent/session-state.ts"() {
|
|
1461
|
+
"use strict";
|
|
1462
|
+
ArtifactStore = class {
|
|
1463
|
+
artifacts = /* @__PURE__ */ new Map();
|
|
1464
|
+
maxArtifacts;
|
|
1465
|
+
maxTotalChars;
|
|
1466
|
+
constructor(opts2) {
|
|
1467
|
+
this.maxArtifacts = opts2?.maxArtifacts ?? 200;
|
|
1468
|
+
this.maxTotalChars = opts2?.maxTotalChars ?? 5e5;
|
|
1469
|
+
}
|
|
1470
|
+
add(a) {
|
|
1471
|
+
while (this.totalChars() + a.raw.length > this.maxTotalChars && this.artifacts.size > 0) {
|
|
1472
|
+
this.evictSizeWeighted();
|
|
1473
|
+
}
|
|
1474
|
+
while (this.artifacts.size >= this.maxArtifacts) {
|
|
1475
|
+
this.evictOldest();
|
|
1476
|
+
}
|
|
1477
|
+
this.artifacts.set(a.id, a);
|
|
1478
|
+
}
|
|
1479
|
+
get(id) {
|
|
1480
|
+
return this.artifacts.get(id);
|
|
1481
|
+
}
|
|
1482
|
+
has(id) {
|
|
1483
|
+
return this.artifacts.has(id);
|
|
1484
|
+
}
|
|
1485
|
+
list() {
|
|
1486
|
+
return [...this.artifacts.values()].sort((a, b) => a.ts < b.ts ? -1 : 1);
|
|
1487
|
+
}
|
|
1488
|
+
recall(ids) {
|
|
1489
|
+
const out = [];
|
|
1490
|
+
for (const id of ids) {
|
|
1491
|
+
const a = this.artifacts.get(id);
|
|
1492
|
+
if (a) out.push({ id, artifact: a });
|
|
1493
|
+
}
|
|
1494
|
+
return out;
|
|
1495
|
+
}
|
|
1496
|
+
size() {
|
|
1497
|
+
return this.artifacts.size;
|
|
1498
|
+
}
|
|
1499
|
+
totalChars() {
|
|
1500
|
+
let sum = 0;
|
|
1501
|
+
for (const a of this.artifacts.values()) {
|
|
1502
|
+
sum += a.raw.length;
|
|
1503
|
+
}
|
|
1504
|
+
return sum;
|
|
1505
|
+
}
|
|
1506
|
+
evictOldest() {
|
|
1507
|
+
let oldest;
|
|
1508
|
+
for (const a of this.artifacts.values()) {
|
|
1509
|
+
if (!oldest || a.ts < oldest.ts) oldest = a;
|
|
1510
|
+
}
|
|
1511
|
+
if (oldest) this.artifacts.delete(oldest.id);
|
|
1512
|
+
}
|
|
1513
|
+
/** Evict the largest artifact among the oldest quartile (by timestamp).
|
|
1514
|
+
* Bounded by the oldest quartile so we never evict freshly-added artifacts;
|
|
1515
|
+
* size-weighted within that window so one big artifact gets dropped instead
|
|
1516
|
+
* of many small ones. */
|
|
1517
|
+
evictSizeWeighted() {
|
|
1518
|
+
const sorted = [...this.artifacts.values()].sort((a, b) => a.ts < b.ts ? -1 : 1);
|
|
1519
|
+
if (sorted.length === 0) return;
|
|
1520
|
+
const quartile = Math.max(1, Math.ceil(sorted.length / 4));
|
|
1521
|
+
const candidates = sorted.slice(0, quartile);
|
|
1522
|
+
let pick3 = candidates[0];
|
|
1523
|
+
for (const a of candidates) {
|
|
1524
|
+
if (a.raw.length > pick3.raw.length) pick3 = a;
|
|
1525
|
+
}
|
|
1526
|
+
this.artifacts.delete(pick3.id);
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
// src/agent/artifact-compaction.ts
|
|
1533
|
+
function approxTokens(n) {
|
|
1534
|
+
return Math.round(n / 3.5);
|
|
1535
|
+
}
|
|
1536
|
+
function estimateMessageTokens(m) {
|
|
1537
|
+
let chars = 0;
|
|
1538
|
+
if (typeof m.content === "string") {
|
|
1539
|
+
chars = m.content.length;
|
|
1540
|
+
} else if (Array.isArray(m.content)) {
|
|
1541
|
+
chars = m.content.map((p) => p.type === "text" ? p.text.length : 0).reduce((a, b) => a + b, 0);
|
|
1542
|
+
}
|
|
1543
|
+
if (m.reasoning_content) chars += m.reasoning_content.length;
|
|
1544
|
+
if (m.tool_calls) {
|
|
1545
|
+
for (const tc of m.tool_calls) {
|
|
1546
|
+
chars += tc.function.name.length + tc.function.arguments.length;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
return approxTokens(chars);
|
|
1550
|
+
}
|
|
1551
|
+
function estimatePromptTokens(messages) {
|
|
1552
|
+
return messages.reduce((sum, m) => sum + estimateMessageTokens(m), 0);
|
|
1553
|
+
}
|
|
1554
|
+
function groupIntoTurns(messages) {
|
|
1555
|
+
const prefix = [];
|
|
1556
|
+
let i = 0;
|
|
1557
|
+
while (i < messages.length && messages[i].role === "system") {
|
|
1558
|
+
prefix.push(messages[i]);
|
|
1559
|
+
i++;
|
|
1560
|
+
}
|
|
1561
|
+
const turns = [];
|
|
1562
|
+
while (i < messages.length) {
|
|
1563
|
+
if (messages[i].role !== "user") {
|
|
1564
|
+
i++;
|
|
1565
|
+
continue;
|
|
1566
|
+
}
|
|
1567
|
+
const user = messages[i];
|
|
1568
|
+
i++;
|
|
1569
|
+
if (i >= messages.length || messages[i].role !== "assistant") {
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1572
|
+
const assistant = messages[i];
|
|
1573
|
+
i++;
|
|
1574
|
+
const tools = [];
|
|
1575
|
+
while (i < messages.length && messages[i].role === "tool") {
|
|
1576
|
+
tools.push(messages[i]);
|
|
1577
|
+
i++;
|
|
1578
|
+
}
|
|
1579
|
+
turns.push({ user, assistant, tools });
|
|
1580
|
+
}
|
|
1581
|
+
return { prefix, turns };
|
|
1582
|
+
}
|
|
1583
|
+
function makeArtifactId(type, index) {
|
|
1584
|
+
return `${type}_${Date.now()}_${index}`;
|
|
1585
|
+
}
|
|
1586
|
+
function extractArtifactsFromTurn(turn, startIndex, store) {
|
|
1587
|
+
const artifacts = [];
|
|
1588
|
+
const stateDelta = {
|
|
1589
|
+
files_touched: [],
|
|
1590
|
+
files_modified: [],
|
|
1591
|
+
confirmed_findings: [],
|
|
1592
|
+
recent_failures: [],
|
|
1593
|
+
decisions: [],
|
|
1594
|
+
next_actions: []
|
|
1595
|
+
};
|
|
1596
|
+
const toolCalls = turn.assistant.tool_calls ?? [];
|
|
1597
|
+
for (let ti = 0; ti < turn.tools.length; ti++) {
|
|
1598
|
+
const tm = turn.tools[ti];
|
|
1599
|
+
const tc = toolCalls[ti];
|
|
1600
|
+
const name = tm.name ?? tc?.function.name ?? "unknown";
|
|
1601
|
+
const content = typeof tm.content === "string" ? tm.content : "";
|
|
1602
|
+
let type = "tool_result";
|
|
1603
|
+
let summary = `${name} result`;
|
|
1604
|
+
let path;
|
|
1605
|
+
if (name === "read") {
|
|
1606
|
+
type = "read_slice";
|
|
1607
|
+
try {
|
|
1608
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1609
|
+
path = args.path;
|
|
1610
|
+
summary = `read ${path ?? "file"}`;
|
|
1611
|
+
if (path && !stateDelta.files_touched.includes(path)) stateDelta.files_touched.push(path);
|
|
1612
|
+
} catch {
|
|
1613
|
+
summary = "read file";
|
|
1614
|
+
}
|
|
1615
|
+
} else if (name === "bash") {
|
|
1616
|
+
type = "bash_log";
|
|
1617
|
+
try {
|
|
1618
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1619
|
+
const cmd = args.command ?? "";
|
|
1620
|
+
summary = `bash: ${cmd.slice(0, 60)}`;
|
|
1621
|
+
if (content.includes("Error") || content.includes("error") || content.includes("FAIL")) {
|
|
1622
|
+
stateDelta.recent_failures.push(`bash failed: ${cmd.slice(0, 80)}`);
|
|
1623
|
+
}
|
|
1624
|
+
} catch {
|
|
1625
|
+
summary = "bash command";
|
|
1626
|
+
}
|
|
1627
|
+
} else if (name === "grep") {
|
|
1628
|
+
type = "grep_result";
|
|
1629
|
+
summary = `grep results (${content.split("\n").length} lines)`;
|
|
1630
|
+
} else if (name === "web_fetch") {
|
|
1631
|
+
type = "web_fetch";
|
|
1632
|
+
try {
|
|
1633
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1634
|
+
summary = `web_fetch: ${args.url ?? "url"}`;
|
|
1635
|
+
} catch {
|
|
1636
|
+
summary = "web_fetch";
|
|
1637
|
+
}
|
|
1638
|
+
} else if (name === "write" || name === "edit") {
|
|
1639
|
+
try {
|
|
1640
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1641
|
+
path = args.path;
|
|
1642
|
+
if (path && !stateDelta.files_modified.includes(path)) stateDelta.files_modified.push(path);
|
|
1643
|
+
if (path && !stateDelta.files_touched.includes(path)) stateDelta.files_touched.push(path);
|
|
1644
|
+
} catch {
|
|
1645
|
+
}
|
|
1646
|
+
continue;
|
|
1647
|
+
} else if (name === "glob") {
|
|
1648
|
+
try {
|
|
1649
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1650
|
+
summary = `glob: ${args.pattern ?? ""}`;
|
|
1651
|
+
} catch {
|
|
1652
|
+
summary = "glob";
|
|
1653
|
+
}
|
|
1654
|
+
} else if (name === "tasks_set") {
|
|
1655
|
+
try {
|
|
1656
|
+
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
1657
|
+
const tasks = args.tasks ?? [];
|
|
1658
|
+
const inProgress = tasks.filter((t) => t.status === "in_progress").map((t) => t.title);
|
|
1659
|
+
const pending = tasks.filter((t) => t.status === "pending").map((t) => t.title);
|
|
1660
|
+
if (inProgress.length) stateDelta.next_actions.push(...inProgress);
|
|
1661
|
+
if (pending.length) stateDelta.next_actions.push(...pending);
|
|
1662
|
+
summary = `tasks_set: ${tasks.length} tasks`;
|
|
1663
|
+
} catch {
|
|
1664
|
+
summary = "tasks_set";
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
const maxRaw = 5e4;
|
|
1668
|
+
const raw = content.length > maxRaw ? content.slice(0, maxRaw) + `
|
|
1669
|
+
...[${content.length - maxRaw} chars truncated]` : content;
|
|
1670
|
+
const artifact = {
|
|
1671
|
+
id: makeArtifactId(type, startIndex + ti),
|
|
1672
|
+
type,
|
|
1673
|
+
summary,
|
|
1674
|
+
raw,
|
|
1675
|
+
source: name,
|
|
1676
|
+
path,
|
|
1677
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
1678
|
+
};
|
|
1679
|
+
artifacts.push(artifact);
|
|
1680
|
+
if (!content.includes("Error") && !content.includes("error") && content.length > 0 && content.length < 2e3) {
|
|
1681
|
+
stateDelta.confirmed_findings.push(`${name}: ${content.slice(0, 200)}`);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
const assistantText = typeof turn.assistant.content === "string" ? turn.assistant.content : "";
|
|
1685
|
+
if (assistantText.length > 0) {
|
|
1686
|
+
const decisionPatterns = [
|
|
1687
|
+
/(?:decided?|will|plan to|going to|should|need to)\s+(.{10,200})/gi,
|
|
1688
|
+
/(?:let's|let us)\s+(.{10,200})/gi
|
|
1689
|
+
];
|
|
1690
|
+
for (const pattern of decisionPatterns) {
|
|
1691
|
+
let match;
|
|
1692
|
+
while ((match = pattern.exec(assistantText)) !== null) {
|
|
1693
|
+
const decision = match[1].trim().replace(/\.$/, "");
|
|
1694
|
+
if (decision.length > 10 && !stateDelta.decisions.includes(decision)) {
|
|
1695
|
+
stateDelta.decisions.push(decision);
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
return { artifacts, stateDelta };
|
|
1701
|
+
}
|
|
1702
|
+
function mergeState(state, delta) {
|
|
1703
|
+
const mergeArr = (a, b) => {
|
|
1704
|
+
if (!b) return a;
|
|
1705
|
+
const set = new Set(a);
|
|
1706
|
+
for (const item of b) set.add(item);
|
|
1707
|
+
return [...set];
|
|
1708
|
+
};
|
|
1709
|
+
return {
|
|
1710
|
+
...state,
|
|
1711
|
+
task: state.task || delta.task || "",
|
|
1712
|
+
user_constraints: mergeArr(state.user_constraints, delta.user_constraints),
|
|
1713
|
+
repo_facts: mergeArr(state.repo_facts, delta.repo_facts),
|
|
1714
|
+
files_touched: mergeArr(state.files_touched, delta.files_touched),
|
|
1715
|
+
files_modified: mergeArr(state.files_modified, delta.files_modified),
|
|
1716
|
+
confirmed_findings: mergeArr(state.confirmed_findings, delta.confirmed_findings),
|
|
1717
|
+
open_questions: mergeArr(state.open_questions, delta.open_questions),
|
|
1718
|
+
recent_failures: mergeArr(state.recent_failures, delta.recent_failures),
|
|
1719
|
+
decisions: mergeArr(state.decisions, delta.decisions),
|
|
1720
|
+
next_actions: mergeArr(state.next_actions, delta.next_actions),
|
|
1721
|
+
artifact_index: { ...state.artifact_index, ...delta.artifact_index }
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
function shouldCompact(opts2) {
|
|
1725
|
+
const tokenThreshold = opts2.tokenThreshold ?? 8e4;
|
|
1726
|
+
const turnThreshold = opts2.turnThreshold ?? 12;
|
|
1727
|
+
const tokens = estimatePromptTokens(opts2.messages);
|
|
1728
|
+
const { turns } = groupIntoTurns(opts2.messages);
|
|
1729
|
+
return tokens > tokenThreshold || turns.length > turnThreshold;
|
|
1730
|
+
}
|
|
1731
|
+
function compactMessagesViaArtifacts(opts2) {
|
|
1732
|
+
const keepLastTurns = opts2.keepLastTurns ?? 4;
|
|
1733
|
+
const { prefix, turns } = groupIntoTurns(opts2.messages);
|
|
1734
|
+
const tokensBefore = estimatePromptTokens(opts2.messages);
|
|
1735
|
+
if (turns.length <= keepLastTurns) {
|
|
1736
|
+
return {
|
|
1737
|
+
newMessages: opts2.messages,
|
|
1738
|
+
newState: opts2.state,
|
|
1739
|
+
metrics: {
|
|
1740
|
+
estimatedTokensBefore: tokensBefore,
|
|
1741
|
+
estimatedTokensAfter: tokensBefore,
|
|
1742
|
+
archivedArtifacts: 0,
|
|
1743
|
+
recalledArtifacts: 0,
|
|
1744
|
+
rawTurnsRemoved: 0,
|
|
1745
|
+
rawTurnsKept: turns.length
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
const toCompact = turns.slice(0, turns.length - keepLastTurns);
|
|
1750
|
+
const toKeep = turns.slice(turns.length - keepLastTurns);
|
|
1751
|
+
let newState = { ...opts2.state };
|
|
1752
|
+
let archivedCount = 0;
|
|
1753
|
+
for (let i = 0; i < toCompact.length; i++) {
|
|
1754
|
+
const turn = toCompact[i];
|
|
1755
|
+
const { artifacts, stateDelta } = extractArtifactsFromTurn(turn, i, opts2.store);
|
|
1756
|
+
for (const artifact of artifacts) {
|
|
1757
|
+
opts2.store.add(artifact);
|
|
1758
|
+
archivedCount++;
|
|
1759
|
+
newState.artifact_index[artifact.id] = {
|
|
1760
|
+
type: artifact.type,
|
|
1761
|
+
summary: artifact.summary,
|
|
1762
|
+
source: artifact.source,
|
|
1763
|
+
path: artifact.path
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
newState = mergeState(newState, stateDelta);
|
|
1767
|
+
if (!newState.task && typeof turn.user.content === "string") {
|
|
1768
|
+
newState.task = turn.user.content.slice(0, 200);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
const workingMemory = [];
|
|
1772
|
+
for (const turn of toKeep) {
|
|
1773
|
+
workingMemory.push(turn.user);
|
|
1774
|
+
workingMemory.push(turn.assistant);
|
|
1775
|
+
for (const tm of turn.tools) {
|
|
1776
|
+
workingMemory.push(tm);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
const stateMsg = buildSessionStateMessage(newState);
|
|
1780
|
+
const newMessages = [...prefix, stateMsg, ...workingMemory];
|
|
1781
|
+
const tokensAfter = estimatePromptTokens(newMessages);
|
|
1782
|
+
const metrics = {
|
|
1783
|
+
estimatedTokensBefore: tokensBefore,
|
|
1784
|
+
estimatedTokensAfter: tokensAfter,
|
|
1785
|
+
archivedArtifacts: archivedCount,
|
|
1786
|
+
recalledArtifacts: 0,
|
|
1787
|
+
rawTurnsRemoved: toCompact.length,
|
|
1788
|
+
rawTurnsKept: toKeep.length
|
|
1789
|
+
};
|
|
1790
|
+
return { newMessages, newState, metrics };
|
|
1791
|
+
}
|
|
1792
|
+
function recallArtifacts(messages, store, state) {
|
|
1793
|
+
const text = messages.map((m) => typeof m.content === "string" ? m.content : "").join(" ");
|
|
1794
|
+
const ids = [];
|
|
1795
|
+
for (const [id, meta] of Object.entries(state.artifact_index)) {
|
|
1796
|
+
if (meta.path && text.includes(meta.path)) {
|
|
1797
|
+
ids.push(id);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
for (const failure of state.recent_failures) {
|
|
1801
|
+
const keyword = failure.split(":")[0];
|
|
1802
|
+
if (!keyword) continue;
|
|
1803
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
1804
|
+
if (!text.toLowerCase().includes(lowerKeyword)) continue;
|
|
1805
|
+
for (const [id, meta] of Object.entries(state.artifact_index)) {
|
|
1806
|
+
if (meta.source === "bash" && !ids.includes(id) && meta.summary.toLowerCase().includes(lowerKeyword)) {
|
|
1807
|
+
ids.push(id);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
const uniqueIds = [...new Set(ids)].slice(0, 5);
|
|
1812
|
+
const recalled = store.recall(uniqueIds);
|
|
1813
|
+
return { ids: uniqueIds, recalled };
|
|
1814
|
+
}
|
|
1815
|
+
var init_artifact_compaction = __esm({
|
|
1816
|
+
"src/agent/artifact-compaction.ts"() {
|
|
1817
|
+
"use strict";
|
|
1818
|
+
init_session_state();
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
|
|
1822
|
+
// src/util/llm-dump.ts
|
|
1823
|
+
import { homedir as homedir5 } from "os";
|
|
1824
|
+
import { join as join8 } from "path";
|
|
1825
|
+
import { mkdirSync as mkdirSync2, appendFileSync, writeFileSync } from "fs";
|
|
1826
|
+
function isLlmDumpEnabled() {
|
|
1827
|
+
const raw = process.env.KIMIFLARE_DUMP_LLM;
|
|
1828
|
+
if (raw === void 0) return false;
|
|
1829
|
+
const v = raw.toLowerCase();
|
|
1830
|
+
return v === "1" || v === "true";
|
|
1831
|
+
}
|
|
1832
|
+
function defaultDumpRoot() {
|
|
1833
|
+
const override = process.env.KIMIFLARE_DUMP_LLM_DIR;
|
|
1834
|
+
if (override && override.trim()) return override;
|
|
1835
|
+
const xdg = process.env.XDG_CONFIG_HOME || join8(homedir5(), ".config");
|
|
1836
|
+
return join8(xdg, "kimiflare", "llm-dumps");
|
|
1837
|
+
}
|
|
1838
|
+
function dumpDir(sessionId) {
|
|
1839
|
+
return join8(defaultDumpRoot(), sessionId && sessionId.trim() ? sessionId : "nosession");
|
|
1840
|
+
}
|
|
1841
|
+
function messageChars(m) {
|
|
1842
|
+
let chars = 0;
|
|
1843
|
+
if (typeof m.content === "string") {
|
|
1844
|
+
chars = m.content.length;
|
|
1845
|
+
} else if (Array.isArray(m.content)) {
|
|
1846
|
+
chars = m.content.reduce((a, p) => a + (p.type === "text" ? p.text.length : 0), 0);
|
|
1847
|
+
}
|
|
1848
|
+
if (m.reasoning_content) chars += m.reasoning_content.length;
|
|
1849
|
+
if (m.tool_calls) {
|
|
1850
|
+
for (const tc of m.tool_calls) {
|
|
1851
|
+
chars += tc.function.name.length + tc.function.arguments.length;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
return chars;
|
|
1855
|
+
}
|
|
1856
|
+
function computeBreakdown(messages, tools) {
|
|
1857
|
+
const perMessage = [];
|
|
1858
|
+
let systemChars = 0;
|
|
1859
|
+
let historyChars = 0;
|
|
1860
|
+
messages.forEach((m, index) => {
|
|
1861
|
+
const chars = messageChars(m);
|
|
1862
|
+
if (m.role === "system") systemChars += chars;
|
|
1863
|
+
else historyChars += chars;
|
|
1864
|
+
perMessage.push({
|
|
1865
|
+
index,
|
|
1866
|
+
role: m.role,
|
|
1867
|
+
...m.name ? { name: m.name } : {},
|
|
1868
|
+
chars,
|
|
1869
|
+
estTokens: approxTokens(chars),
|
|
1870
|
+
...m.tool_calls && m.tool_calls.length ? { toolName: m.tool_calls.map((t) => t.function.name).join(",") } : {}
|
|
1871
|
+
});
|
|
1872
|
+
});
|
|
1873
|
+
const toolsChars = tools.reduce(
|
|
1874
|
+
(a, t) => a + t.function.name.length + t.function.description.length + JSON.stringify(t.function.parameters).length,
|
|
1875
|
+
0
|
|
1876
|
+
);
|
|
1877
|
+
const totalChars = systemChars + historyChars + toolsChars;
|
|
1878
|
+
return {
|
|
1879
|
+
totalChars,
|
|
1880
|
+
estTokens: approxTokens(totalChars),
|
|
1881
|
+
messageCount: messages.length,
|
|
1882
|
+
toolCount: tools.length,
|
|
1883
|
+
systemChars,
|
|
1884
|
+
toolsChars,
|
|
1885
|
+
historyChars,
|
|
1886
|
+
perMessage
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
function safeSegment(s) {
|
|
1890
|
+
return s.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
1891
|
+
}
|
|
1892
|
+
function writeLlmDump(record) {
|
|
1893
|
+
if (!isLlmDumpEnabled()) return;
|
|
1894
|
+
try {
|
|
1895
|
+
const dir = dumpDir(record.meta.sessionId);
|
|
1896
|
+
mkdirSync2(dir, { recursive: true });
|
|
1897
|
+
const tsPart = safeSegment(record.meta.ts);
|
|
1898
|
+
const turnPart = safeSegment(record.meta.turnId ?? "noturn");
|
|
1899
|
+
const reqPart = safeSegment(record.meta.requestId);
|
|
1900
|
+
const file = join8(dir, `${tsPart}-${turnPart}-${reqPart}.json`);
|
|
1901
|
+
writeFileSync(file, JSON.stringify(record, null, 2));
|
|
1902
|
+
const summary = {
|
|
1903
|
+
...record.meta,
|
|
1904
|
+
...record.breakdown,
|
|
1905
|
+
perMessage: void 0,
|
|
1906
|
+
// keep the index line thin
|
|
1907
|
+
finishReason: record.response.finishReason,
|
|
1908
|
+
usage: record.response.usage,
|
|
1909
|
+
file
|
|
1910
|
+
};
|
|
1911
|
+
appendFileSync(join8(dir, "index.jsonl"), JSON.stringify(summary) + "\n");
|
|
1912
|
+
} catch {
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
var init_llm_dump = __esm({
|
|
1916
|
+
"src/util/llm-dump.ts"() {
|
|
1917
|
+
"use strict";
|
|
1918
|
+
init_artifact_compaction();
|
|
1919
|
+
}
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1366
1922
|
// src/models/registry.ts
|
|
1367
1923
|
function isUnifiedEligible(entry) {
|
|
1368
1924
|
if (entry.provider === "workers-ai") return false;
|
|
@@ -1485,6 +2041,38 @@ async function* runKimi(opts2) {
|
|
|
1485
2041
|
if (opts2.reasoningEffort && supportsReasoning) {
|
|
1486
2042
|
body.reasoning_effort = opts2.reasoningEffort;
|
|
1487
2043
|
}
|
|
2044
|
+
let dumpRecord = null;
|
|
2045
|
+
if (isLlmDumpEnabled()) {
|
|
2046
|
+
const dumpMessages = body.messages;
|
|
2047
|
+
const dumpTools = body.tools ?? [];
|
|
2048
|
+
const { messages: _m, tools: _t, ...params } = body;
|
|
2049
|
+
const dumpResponse = {
|
|
2050
|
+
text: "",
|
|
2051
|
+
reasoning: "",
|
|
2052
|
+
toolCalls: [],
|
|
2053
|
+
finishReason: null,
|
|
2054
|
+
usage: null
|
|
2055
|
+
};
|
|
2056
|
+
dumpRecord = {
|
|
2057
|
+
meta: {
|
|
2058
|
+
requestId,
|
|
2059
|
+
sessionId: opts2.sessionId ?? getLogSessionId(),
|
|
2060
|
+
turnId: getLogTurnId(),
|
|
2061
|
+
model: opts2.model,
|
|
2062
|
+
url,
|
|
2063
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
2064
|
+
},
|
|
2065
|
+
request: {
|
|
2066
|
+
system: dumpMessages.filter((m) => m.role === "system"),
|
|
2067
|
+
messages: dumpMessages,
|
|
2068
|
+
tools: dumpTools,
|
|
2069
|
+
params,
|
|
2070
|
+
rawSerialized: stableStringify(body, jsonReplacer)
|
|
2071
|
+
},
|
|
2072
|
+
breakdown: computeBreakdown(dumpMessages, dumpTools),
|
|
2073
|
+
response: dumpResponse
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
1488
2076
|
logger.debug("runKimi:request", { requestId, attempt: 0, model: opts2.model });
|
|
1489
2077
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
1490
2078
|
let res;
|
|
@@ -1565,13 +2153,41 @@ async function* runKimi(opts2) {
|
|
|
1565
2153
|
const meta = readGatewayMeta(res.headers);
|
|
1566
2154
|
if (meta) yield { type: "gateway_meta", meta };
|
|
1567
2155
|
logger.debug("runKimi:stream_start", { requestId });
|
|
1568
|
-
|
|
1569
|
-
|
|
2156
|
+
try {
|
|
2157
|
+
for await (const ev of parseStream(res.body, opts2.signal, opts2.idleTimeoutMs, opts2.postFirstByteIdleTimeoutMs)) {
|
|
2158
|
+
if (dumpRecord) accumulateDumpResponse(dumpRecord.response, ev);
|
|
2159
|
+
yield ev;
|
|
2160
|
+
}
|
|
2161
|
+
} finally {
|
|
2162
|
+
if (dumpRecord) {
|
|
2163
|
+
dumpRecord.meta.attempt = attempt;
|
|
2164
|
+
writeLlmDump(dumpRecord);
|
|
2165
|
+
}
|
|
1570
2166
|
}
|
|
1571
2167
|
logger.debug("runKimi:stream_end", { requestId });
|
|
1572
2168
|
return;
|
|
1573
2169
|
}
|
|
1574
2170
|
}
|
|
2171
|
+
function accumulateDumpResponse(resp, ev) {
|
|
2172
|
+
switch (ev.type) {
|
|
2173
|
+
case "text":
|
|
2174
|
+
resp.text += ev.delta;
|
|
2175
|
+
break;
|
|
2176
|
+
case "reasoning":
|
|
2177
|
+
resp.reasoning += ev.delta;
|
|
2178
|
+
break;
|
|
2179
|
+
case "tool_call_complete":
|
|
2180
|
+
resp.toolCalls.push({ name: ev.name, arguments: ev.arguments });
|
|
2181
|
+
break;
|
|
2182
|
+
case "usage":
|
|
2183
|
+
resp.usage = ev.usage;
|
|
2184
|
+
break;
|
|
2185
|
+
case "done":
|
|
2186
|
+
resp.finishReason = ev.finishReason;
|
|
2187
|
+
if (ev.usage) resp.usage = ev.usage;
|
|
2188
|
+
break;
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
1575
2191
|
function validateModelId(model) {
|
|
1576
2192
|
if (!model) throw new KimiApiError(`Invalid model ID: ${model}`, 400);
|
|
1577
2193
|
if (/^@[a-zA-Z0-9_-]+\/[a-zA-Z0-9._-]+(\/[a-zA-Z0-9._-]+)*$/.test(model)) return;
|
|
@@ -1823,6 +2439,8 @@ var init_client = __esm({
|
|
|
1823
2439
|
init_version();
|
|
1824
2440
|
init_messages();
|
|
1825
2441
|
init_logger();
|
|
2442
|
+
init_log_sink();
|
|
2443
|
+
init_llm_dump();
|
|
1826
2444
|
init_registry();
|
|
1827
2445
|
RETRYABLE_CODES = /* @__PURE__ */ new Set([3040]);
|
|
1828
2446
|
MAX_ATTEMPTS = 5;
|
|
@@ -1869,20 +2487,45 @@ var init_registry2 = __esm({
|
|
|
1869
2487
|
}
|
|
1870
2488
|
});
|
|
1871
2489
|
|
|
1872
|
-
// src/
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
2490
|
+
// src/memory/recall-inject.ts
|
|
2491
|
+
function hasRecalledMemory(messages) {
|
|
2492
|
+
return messages.some(
|
|
2493
|
+
(m) => m.role === "system" && typeof m.content === "string" && m.content.startsWith(RECALLED_MEMORY_HEADER)
|
|
2494
|
+
);
|
|
2495
|
+
}
|
|
2496
|
+
function injectRecalledMemoryOnce(messages, text) {
|
|
2497
|
+
if (!text || hasRecalledMemory(messages)) return false;
|
|
2498
|
+
const lastSystemIdx = messages.findLastIndex((m) => m.role === "system");
|
|
2499
|
+
const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : messages.length;
|
|
2500
|
+
messages.splice(insertIdx, 0, {
|
|
2501
|
+
role: "system",
|
|
2502
|
+
content: `${RECALLED_MEMORY_HEADER}
|
|
2503
|
+
${text}`
|
|
2504
|
+
});
|
|
2505
|
+
return true;
|
|
2506
|
+
}
|
|
2507
|
+
var RECALLED_MEMORY_HEADER;
|
|
2508
|
+
var init_recall_inject = __esm({
|
|
2509
|
+
"src/memory/recall-inject.ts"() {
|
|
2510
|
+
"use strict";
|
|
2511
|
+
RECALLED_MEMORY_HEADER = "[recalled project memory]";
|
|
2512
|
+
}
|
|
2513
|
+
});
|
|
2514
|
+
|
|
2515
|
+
// src/storage-limits.ts
|
|
2516
|
+
import { readdir as readdir2, stat as stat2, unlink } from "fs/promises";
|
|
2517
|
+
import { join as join9 } from "path";
|
|
2518
|
+
async function listFilesByMtime(dir, pattern = /.*/) {
|
|
2519
|
+
let entries;
|
|
2520
|
+
try {
|
|
2521
|
+
entries = await readdir2(dir);
|
|
1879
2522
|
} catch {
|
|
1880
2523
|
return [];
|
|
1881
2524
|
}
|
|
1882
2525
|
const files = [];
|
|
1883
2526
|
for (const name of entries) {
|
|
1884
2527
|
if (!pattern.test(name)) continue;
|
|
1885
|
-
const p =
|
|
2528
|
+
const p = join9(dir, name);
|
|
1886
2529
|
try {
|
|
1887
2530
|
const s = await stat2(p);
|
|
1888
2531
|
if (s.isFile()) files.push({ path: p, mtime: s.mtime });
|
|
@@ -1966,19 +2609,19 @@ var init_storage_limits = __esm({
|
|
|
1966
2609
|
|
|
1967
2610
|
// src/cost-debug.ts
|
|
1968
2611
|
import { appendFile, mkdir as mkdir5 } from "fs/promises";
|
|
1969
|
-
import { homedir as
|
|
1970
|
-
import { join as
|
|
2612
|
+
import { homedir as homedir6 } from "os";
|
|
2613
|
+
import { join as join10 } from "path";
|
|
1971
2614
|
function debugDir() {
|
|
1972
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
1973
|
-
return
|
|
2615
|
+
const xdg = process.env.XDG_DATA_HOME || join10(homedir6(), ".local", "share");
|
|
2616
|
+
return join10(xdg, "kimiflare");
|
|
1974
2617
|
}
|
|
1975
2618
|
function debugPath() {
|
|
1976
|
-
return
|
|
2619
|
+
return join10(debugDir(), "cost-debug.jsonl");
|
|
1977
2620
|
}
|
|
1978
2621
|
function now() {
|
|
1979
2622
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1980
2623
|
}
|
|
1981
|
-
function
|
|
2624
|
+
function approxTokens2(chars) {
|
|
1982
2625
|
return Math.round(chars / 4);
|
|
1983
2626
|
}
|
|
1984
2627
|
function analyzePrompt(messages) {
|
|
@@ -1994,14 +2637,14 @@ function analyzePrompt(messages) {
|
|
|
1994
2637
|
const base = {
|
|
1995
2638
|
role: m.role,
|
|
1996
2639
|
chars,
|
|
1997
|
-
approxTokens:
|
|
2640
|
+
approxTokens: approxTokens2(chars)
|
|
1998
2641
|
};
|
|
1999
2642
|
if (m.role === "assistant" && m.reasoning_content) {
|
|
2000
2643
|
sections.push({
|
|
2001
2644
|
...base,
|
|
2002
|
-
detail: `content+reasoning (${
|
|
2645
|
+
detail: `content+reasoning (${approxTokens2(m.reasoning_content.length)} reasoning tokens)`,
|
|
2003
2646
|
chars: chars + m.reasoning_content.length,
|
|
2004
|
-
approxTokens:
|
|
2647
|
+
approxTokens: approxTokens2(chars + m.reasoning_content.length)
|
|
2005
2648
|
});
|
|
2006
2649
|
} else if (m.role === "tool") {
|
|
2007
2650
|
sections.push({
|
|
@@ -2110,7 +2753,7 @@ async function logTurnDebug(ctx) {
|
|
|
2110
2753
|
usage: ctx.usage,
|
|
2111
2754
|
promptSections,
|
|
2112
2755
|
promptTotalChars,
|
|
2113
|
-
promptTotalApproxTokens:
|
|
2756
|
+
promptTotalApproxTokens: approxTokens2(promptTotalChars),
|
|
2114
2757
|
toolStats,
|
|
2115
2758
|
toolTotalRawBytes: toolTotalRaw,
|
|
2116
2759
|
toolTotalReducedBytes: toolTotalReduced,
|
|
@@ -2634,757 +3277,301 @@ var require_node_gyp_build = __commonJS({
|
|
|
2634
3277
|
function compareTags(runtime2) {
|
|
2635
3278
|
return function(a, b) {
|
|
2636
3279
|
if (a.runtime !== b.runtime) {
|
|
2637
|
-
return a.runtime === runtime2 ? -1 : 1;
|
|
2638
|
-
} else if (a.abi !== b.abi) {
|
|
2639
|
-
return a.abi ? -1 : 1;
|
|
2640
|
-
} else if (a.specificity !== b.specificity) {
|
|
2641
|
-
return a.specificity > b.specificity ? -1 : 1;
|
|
2642
|
-
} else {
|
|
2643
|
-
return 0;
|
|
2644
|
-
}
|
|
2645
|
-
};
|
|
2646
|
-
}
|
|
2647
|
-
function isNwjs() {
|
|
2648
|
-
return !!(process.versions && process.versions.nw);
|
|
2649
|
-
}
|
|
2650
|
-
function isElectron() {
|
|
2651
|
-
if (process.versions && process.versions.electron) return true;
|
|
2652
|
-
if (process.env.ELECTRON_RUN_AS_NODE) return true;
|
|
2653
|
-
return typeof window !== "undefined" && window.process && window.process.type === "renderer";
|
|
2654
|
-
}
|
|
2655
|
-
function isAlpine(platform9) {
|
|
2656
|
-
return platform9 === "linux" && fs.existsSync("/etc/alpine-release");
|
|
2657
|
-
}
|
|
2658
|
-
load.parseTags = parseTags;
|
|
2659
|
-
load.matchTags = matchTags;
|
|
2660
|
-
load.compareTags = compareTags;
|
|
2661
|
-
load.parseTuple = parseTuple;
|
|
2662
|
-
load.matchTuple = matchTuple;
|
|
2663
|
-
load.compareTuples = compareTuples;
|
|
2664
|
-
}
|
|
2665
|
-
});
|
|
2666
|
-
|
|
2667
|
-
// node_modules/node-gyp-build/index.js
|
|
2668
|
-
var require_node_gyp_build2 = __commonJS({
|
|
2669
|
-
"node_modules/node-gyp-build/index.js"(exports, module) {
|
|
2670
|
-
"use strict";
|
|
2671
|
-
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
2672
|
-
if (typeof runtimeRequire.addon === "function") {
|
|
2673
|
-
module.exports = runtimeRequire.addon.bind(runtimeRequire);
|
|
2674
|
-
} else {
|
|
2675
|
-
module.exports = require_node_gyp_build();
|
|
2676
|
-
}
|
|
2677
|
-
}
|
|
2678
|
-
});
|
|
2679
|
-
|
|
2680
|
-
// node_modules/isolated-vm/isolated-vm.js
|
|
2681
|
-
var require_isolated_vm = __commonJS({
|
|
2682
|
-
"node_modules/isolated-vm/isolated-vm.js"(exports, module) {
|
|
2683
|
-
"use strict";
|
|
2684
|
-
module.exports = require_node_gyp_build2()(__dirname).ivm;
|
|
2685
|
-
}
|
|
2686
|
-
});
|
|
2687
|
-
|
|
2688
|
-
// src/code-mode/sandbox.ts
|
|
2689
|
-
import { join as join10, dirname as dirname5 } from "path";
|
|
2690
|
-
import { pathToFileURL } from "url";
|
|
2691
|
-
function stripTypescript(code) {
|
|
2692
|
-
let js = code;
|
|
2693
|
-
js = js.replace(/interface\s+\w+\s*\{[\s\S]*?\n\}/g, "");
|
|
2694
|
-
js = js.replace(/type\s+\w+\s*=\s*[^;]+;/g, "");
|
|
2695
|
-
js = js.replace(/(\w+)<[^>]+>(\s*\()/g, "$1$2");
|
|
2696
|
-
js = js.replace(/(\b(?:const|let|var)\s+\w+)\s*:\s*[^=;]+/g, "$1");
|
|
2697
|
-
js = js.replace(/(\(|,\s*)(\w+)\s*:\s*[^,)=]+/g, "$1$2");
|
|
2698
|
-
js = js.replace(/(\)[\s]*)\s*:\s*[^{]+(\s*\{)/g, "$1$2");
|
|
2699
|
-
js = js.replace(/(\)[\s]*)\s*:\s*Promise<[^>]+>(\s*\{)/g, "$1$2");
|
|
2700
|
-
js = js.replace(/\s+as\s+\w+(?:\[\])?/g, "");
|
|
2701
|
-
js = js.replace(/(\w+)(\??)!/g, "$1$2");
|
|
2702
|
-
js = js.replace(/import\s+type\s+[^;]+;/g, "");
|
|
2703
|
-
js = js.replace(/declare\s+[^;]+;/g, "");
|
|
2704
|
-
js = js.replace(/\n{3,}/g, "\n\n");
|
|
2705
|
-
return js.trim();
|
|
2706
|
-
}
|
|
2707
|
-
async function loadTypescript(cwd) {
|
|
2708
|
-
try {
|
|
2709
|
-
const tsPath = await import.meta.resolve("typescript");
|
|
2710
|
-
return await import(tsPath);
|
|
2711
|
-
} catch {
|
|
2712
|
-
}
|
|
2713
|
-
let dir = cwd;
|
|
2714
|
-
while (dir !== dirname5(dir)) {
|
|
2715
|
-
try {
|
|
2716
|
-
const tsPath = join10(dir, "node_modules", "typescript", "lib", "typescript.js");
|
|
2717
|
-
return await import(pathToFileURL(tsPath).href);
|
|
2718
|
-
} catch {
|
|
2719
|
-
}
|
|
2720
|
-
dir = dirname5(dir);
|
|
2721
|
-
}
|
|
2722
|
-
return null;
|
|
2723
|
-
}
|
|
2724
|
-
async function transpileOrStrip(code, cwd) {
|
|
2725
|
-
const ts = await loadTypescript(cwd);
|
|
2726
|
-
if (ts) {
|
|
2727
|
-
const result = ts.transpileModule(code, {
|
|
2728
|
-
compilerOptions: {
|
|
2729
|
-
module: ts.ModuleKind.ES2022,
|
|
2730
|
-
target: ts.ScriptTarget.ES2022,
|
|
2731
|
-
esModuleInterop: true,
|
|
2732
|
-
isolatedModules: true
|
|
2733
|
-
}
|
|
2734
|
-
});
|
|
2735
|
-
return { js: result.outputText, warnings: [] };
|
|
2736
|
-
}
|
|
2737
|
-
return {
|
|
2738
|
-
js: stripTypescript(code),
|
|
2739
|
-
warnings: ["TypeScript not found in node_modules. Using fallback parser; install typescript for reliable transpilation."]
|
|
2740
|
-
};
|
|
2741
|
-
}
|
|
2742
|
-
async function runWithIsolatedVm(opts2) {
|
|
2743
|
-
const { Isolate } = await Promise.resolve().then(() => __toESM(require_isolated_vm(), 1));
|
|
2744
|
-
const isolate = new Isolate({ memoryLimit: opts2.memoryLimitMB ?? 128 });
|
|
2745
|
-
const context = await isolate.createContext();
|
|
2746
|
-
const jail = context.global;
|
|
2747
|
-
await jail.set("global", jail.derefInto());
|
|
2748
|
-
const logs = [];
|
|
2749
|
-
const toolCalls = [];
|
|
2750
|
-
await context.evalClosure(
|
|
2751
|
-
`globalThis._log = function(...args) {
|
|
2752
|
-
$0.applySync(undefined, [args.map(String).join(" ")], { arguments: { copy: true } });
|
|
2753
|
-
};`,
|
|
2754
|
-
[(msg) => logs.push(msg)],
|
|
2755
|
-
{ arguments: { reference: true } }
|
|
2756
|
-
);
|
|
2757
|
-
await context.eval(`var console = { log: function(...args) { _log(args.map(String).join(" ")); } };`);
|
|
2758
|
-
const toolMap = new Map(opts2.tools.map((t) => [t.name, t]));
|
|
2759
|
-
for (const tool of opts2.tools) {
|
|
2760
|
-
const ref = new (await Promise.resolve().then(() => __toESM(require_isolated_vm(), 1))).Reference(
|
|
2761
|
-
async (argsJson) => {
|
|
2762
|
-
const args = JSON.parse(argsJson);
|
|
2763
|
-
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2764
|
-
const result = await opts2.executor.run(
|
|
2765
|
-
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
2766
|
-
opts2.askPermission,
|
|
2767
|
-
opts2.ctx
|
|
2768
|
-
);
|
|
2769
|
-
toolCalls.push({
|
|
2770
|
-
name: tool.name,
|
|
2771
|
-
args,
|
|
2772
|
-
result: result.content
|
|
2773
|
-
});
|
|
2774
|
-
return result.content;
|
|
2775
|
-
}
|
|
2776
|
-
);
|
|
2777
|
-
await context.evalClosure(
|
|
2778
|
-
`globalThis["_api_${tool.name}"] = function(argsJson) {
|
|
2779
|
-
return $0.applySyncPromise(undefined, [argsJson], { arguments: { copy: true } });
|
|
2780
|
-
};`,
|
|
2781
|
-
[ref],
|
|
2782
|
-
{ arguments: { reference: true } }
|
|
2783
|
-
);
|
|
2784
|
-
}
|
|
2785
|
-
const apiMethods = opts2.tools.map((t) => ` ${t.name}: function(input) { return _api_${t.name}(JSON.stringify(input ?? {})); }`).join(",\n");
|
|
2786
|
-
await context.eval(`var api = {
|
|
2787
|
-
${apiMethods}
|
|
2788
|
-
};`);
|
|
2789
|
-
const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
|
|
2790
|
-
const wrapped = `(async function() {
|
|
2791
|
-
${jsCode}
|
|
2792
|
-
})();`;
|
|
2793
|
-
try {
|
|
2794
|
-
const timeout = opts2.timeoutMs ?? 3e4;
|
|
2795
|
-
const script = await isolate.compileScript(wrapped);
|
|
2796
|
-
await script.run(context, { timeout, release: true });
|
|
2797
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
2798
|
-
} catch (err) {
|
|
2799
|
-
const message2 = err instanceof Error ? err.message : String(err);
|
|
2800
|
-
return { output: "", logs, error: message2, toolCalls, warnings };
|
|
2801
|
-
} finally {
|
|
2802
|
-
isolate.dispose();
|
|
2803
|
-
}
|
|
2804
|
-
return { output: logs.join("\n"), logs, toolCalls, warnings };
|
|
2805
|
-
}
|
|
2806
|
-
async function runWithNodeVm(opts2) {
|
|
2807
|
-
const { runInNewContext } = await import("vm");
|
|
2808
|
-
const logs = [];
|
|
2809
|
-
const toolCalls = [];
|
|
2810
|
-
const sandbox = {
|
|
2811
|
-
console: {
|
|
2812
|
-
log: (...args) => {
|
|
2813
|
-
logs.push(args.map(String).join(" "));
|
|
2814
|
-
}
|
|
2815
|
-
},
|
|
2816
|
-
api: {},
|
|
2817
|
-
setTimeout,
|
|
2818
|
-
clearTimeout,
|
|
2819
|
-
setInterval,
|
|
2820
|
-
clearInterval,
|
|
2821
|
-
Promise,
|
|
2822
|
-
JSON,
|
|
2823
|
-
Math,
|
|
2824
|
-
Date,
|
|
2825
|
-
Array,
|
|
2826
|
-
Object,
|
|
2827
|
-
String,
|
|
2828
|
-
Number,
|
|
2829
|
-
Boolean,
|
|
2830
|
-
RegExp,
|
|
2831
|
-
Error,
|
|
2832
|
-
TypeError,
|
|
2833
|
-
RangeError,
|
|
2834
|
-
SyntaxError,
|
|
2835
|
-
ReferenceError,
|
|
2836
|
-
Map,
|
|
2837
|
-
Set,
|
|
2838
|
-
WeakMap,
|
|
2839
|
-
WeakSet,
|
|
2840
|
-
Symbol,
|
|
2841
|
-
parseInt,
|
|
2842
|
-
parseFloat,
|
|
2843
|
-
isNaN,
|
|
2844
|
-
isFinite,
|
|
2845
|
-
encodeURI,
|
|
2846
|
-
decodeURI,
|
|
2847
|
-
encodeURIComponent,
|
|
2848
|
-
decodeURIComponent,
|
|
2849
|
-
escape,
|
|
2850
|
-
unescape,
|
|
2851
|
-
Infinity: Infinity,
|
|
2852
|
-
NaN: NaN,
|
|
2853
|
-
undefined: void 0
|
|
2854
|
-
};
|
|
2855
|
-
for (const tool of opts2.tools) {
|
|
2856
|
-
sandbox.api[tool.name] = async (input) => {
|
|
2857
|
-
const args = input ?? {};
|
|
2858
|
-
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2859
|
-
const result = await opts2.executor.run(
|
|
2860
|
-
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
2861
|
-
opts2.askPermission,
|
|
2862
|
-
opts2.ctx
|
|
2863
|
-
);
|
|
2864
|
-
toolCalls.push({
|
|
2865
|
-
name: tool.name,
|
|
2866
|
-
args,
|
|
2867
|
-
result: result.content
|
|
2868
|
-
});
|
|
2869
|
-
return result.content;
|
|
2870
|
-
};
|
|
2871
|
-
}
|
|
2872
|
-
const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
|
|
2873
|
-
const wrapped = `"use strict";
|
|
2874
|
-
(async function() {
|
|
2875
|
-
${jsCode}
|
|
2876
|
-
})();`;
|
|
2877
|
-
try {
|
|
2878
|
-
const timeout = opts2.timeoutMs ?? 3e4;
|
|
2879
|
-
await runInNewContext(wrapped, sandbox, { timeout, displayErrors: true });
|
|
2880
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
2881
|
-
} catch (err) {
|
|
2882
|
-
const message2 = err instanceof Error ? err.message : String(err);
|
|
2883
|
-
return { output: "", logs, error: message2, toolCalls, warnings };
|
|
2884
|
-
}
|
|
2885
|
-
return { output: logs.join("\n"), logs, toolCalls, warnings };
|
|
2886
|
-
}
|
|
2887
|
-
function buildFallbackWarning(errMessage) {
|
|
2888
|
-
let reason;
|
|
2889
|
-
let fix;
|
|
2890
|
-
if (errMessage.includes("Cannot find module") || errMessage.includes("isolated-vm")) {
|
|
2891
|
-
reason = "The optional dependency `isolated-vm` is not installed.";
|
|
2892
|
-
fix = "Run `npm install isolated-vm` in your project (or `npm install -g isolated-vm` if KimiFlare is installed globally).";
|
|
2893
|
-
} else if (errMessage.includes("bindings") || errMessage.includes(".node")) {
|
|
2894
|
-
reason = "The `isolated-vm` native bindings are incompatible with this Node version or architecture.";
|
|
2895
|
-
fix = "Try `npm rebuild isolated-vm`, or switch to Node 22 LTS if you're on Apple Silicon.";
|
|
2896
|
-
} else {
|
|
2897
|
-
reason = "The secure sandbox (`isolated-vm`) could not be loaded.";
|
|
2898
|
-
fix = "Ensure build tools are installed, then run `npm install isolated-vm`.";
|
|
2899
|
-
}
|
|
2900
|
-
return `Code Mode is using the built-in Node.js sandbox. Tool execution works normally, but without memory limits or full process isolation. ${reason} ${fix}`;
|
|
2901
|
-
}
|
|
2902
|
-
async function runInSandbox(opts2) {
|
|
2903
|
-
try {
|
|
2904
|
-
return await runWithIsolatedVm(opts2);
|
|
2905
|
-
} catch (err) {
|
|
2906
|
-
const message2 = err instanceof Error ? err.message : String(err);
|
|
2907
|
-
const result = await runWithNodeVm(opts2);
|
|
2908
|
-
const sessionKey = opts2.ctx.sessionId ?? NO_SESSION_KEY;
|
|
2909
|
-
if (!fallbackWarningShownSessions.has(sessionKey)) {
|
|
2910
|
-
fallbackWarningShownSessions.add(sessionKey);
|
|
2911
|
-
const warning = buildFallbackWarning(message2);
|
|
2912
|
-
return { ...result, warnings: [warning, ...result.warnings ?? []] };
|
|
2913
|
-
}
|
|
2914
|
-
return result;
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
var fallbackWarningShownSessions, NO_SESSION_KEY;
|
|
2918
|
-
var init_sandbox = __esm({
|
|
2919
|
-
"src/code-mode/sandbox.ts"() {
|
|
2920
|
-
"use strict";
|
|
2921
|
-
fallbackWarningShownSessions = /* @__PURE__ */ new Set();
|
|
2922
|
-
NO_SESSION_KEY = "__no_session__";
|
|
2923
|
-
}
|
|
2924
|
-
});
|
|
2925
|
-
|
|
2926
|
-
// src/code-mode/index.ts
|
|
2927
|
-
var init_code_mode = __esm({
|
|
2928
|
-
"src/code-mode/index.ts"() {
|
|
2929
|
-
"use strict";
|
|
2930
|
-
init_api_generator();
|
|
2931
|
-
init_sandbox();
|
|
2932
|
-
}
|
|
2933
|
-
});
|
|
2934
|
-
|
|
2935
|
-
// src/agent/session-state.ts
|
|
2936
|
-
function emptySessionState(task = "") {
|
|
2937
|
-
return {
|
|
2938
|
-
task,
|
|
2939
|
-
user_constraints: [],
|
|
2940
|
-
repo_facts: [],
|
|
2941
|
-
files_touched: [],
|
|
2942
|
-
files_modified: [],
|
|
2943
|
-
confirmed_findings: [],
|
|
2944
|
-
open_questions: [],
|
|
2945
|
-
recent_failures: [],
|
|
2946
|
-
decisions: [],
|
|
2947
|
-
next_actions: [],
|
|
2948
|
-
artifact_index: {}
|
|
2949
|
-
};
|
|
2950
|
-
}
|
|
2951
|
-
function serializeArtifactStore(store) {
|
|
2952
|
-
const MAX_ARTIFACT_CHARS = 5e4;
|
|
2953
|
-
const out = [];
|
|
2954
|
-
for (const a of store.list()) {
|
|
2955
|
-
out.push({
|
|
2956
|
-
id: a.id,
|
|
2957
|
-
type: a.type,
|
|
2958
|
-
summary: a.summary,
|
|
2959
|
-
raw: a.raw.slice(0, MAX_ARTIFACT_CHARS),
|
|
2960
|
-
source: a.source,
|
|
2961
|
-
path: a.path,
|
|
2962
|
-
lineRange: a.lineRange,
|
|
2963
|
-
ts: a.ts
|
|
2964
|
-
});
|
|
2965
|
-
}
|
|
2966
|
-
return out;
|
|
2967
|
-
}
|
|
2968
|
-
function deserializeArtifactStore(data) {
|
|
2969
|
-
const store = new ArtifactStore();
|
|
2970
|
-
for (const a of data) {
|
|
2971
|
-
store.add({
|
|
2972
|
-
id: a.id,
|
|
2973
|
-
type: a.type,
|
|
2974
|
-
summary: a.summary,
|
|
2975
|
-
raw: a.raw,
|
|
2976
|
-
source: a.source,
|
|
2977
|
-
path: a.path,
|
|
2978
|
-
lineRange: a.lineRange,
|
|
2979
|
-
ts: a.ts
|
|
2980
|
-
});
|
|
2981
|
-
}
|
|
2982
|
-
return store;
|
|
2983
|
-
}
|
|
2984
|
-
function formatRecalledArtifacts(recalled) {
|
|
2985
|
-
if (recalled.length === 0) return "";
|
|
2986
|
-
const lines = ["[recalled artifacts]"];
|
|
2987
|
-
for (const { id, artifact } of recalled) {
|
|
2988
|
-
lines.push(`--- artifact:${id} (${artifact.type} from ${artifact.source}) ---`);
|
|
2989
|
-
lines.push(artifact.raw);
|
|
2990
|
-
}
|
|
2991
|
-
return lines.join("\n");
|
|
2992
|
-
}
|
|
2993
|
-
function serializeSessionState(state) {
|
|
2994
|
-
const lines = [];
|
|
2995
|
-
lines.push(`task: ${state.task || "(none)"}`);
|
|
2996
|
-
if (state.user_constraints.length) lines.push(`constraints:
|
|
2997
|
-
${state.user_constraints.map((c) => " - " + c).join("\n")}`);
|
|
2998
|
-
if (state.repo_facts.length) lines.push(`repo_facts:
|
|
2999
|
-
${state.repo_facts.map((f) => " - " + f).join("\n")}`);
|
|
3000
|
-
if (state.files_touched.length) lines.push(`files_touched: ${state.files_touched.join(", ")}`);
|
|
3001
|
-
if (state.files_modified.length) lines.push(`files_modified: ${state.files_modified.join(", ")}`);
|
|
3002
|
-
if (state.confirmed_findings.length) lines.push(`findings:
|
|
3003
|
-
${state.confirmed_findings.map((f) => " - " + f).join("\n")}`);
|
|
3004
|
-
if (state.open_questions.length) lines.push(`open_questions:
|
|
3005
|
-
${state.open_questions.map((q) => " - " + q).join("\n")}`);
|
|
3006
|
-
if (state.recent_failures.length) lines.push(`recent_failures:
|
|
3007
|
-
${state.recent_failures.map((f) => " - " + f).join("\n")}`);
|
|
3008
|
-
if (state.decisions.length) lines.push(`decisions:
|
|
3009
|
-
${state.decisions.map((d) => " - " + d).join("\n")}`);
|
|
3010
|
-
if (state.next_actions.length) lines.push(`next_actions:
|
|
3011
|
-
${state.next_actions.map((a) => " - " + a).join("\n")}`);
|
|
3012
|
-
if (Object.keys(state.artifact_index).length) {
|
|
3013
|
-
lines.push("artifact_index:");
|
|
3014
|
-
for (const [id, meta] of Object.entries(state.artifact_index)) {
|
|
3015
|
-
lines.push(` ${id}: [${meta.type}] ${meta.summary}`);
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
return lines.join("\n");
|
|
3019
|
-
}
|
|
3020
|
-
function buildSessionStateMessage(state) {
|
|
3021
|
-
return {
|
|
3022
|
-
role: "system",
|
|
3023
|
-
content: `[compiled session state]
|
|
3024
|
-
${serializeSessionState(state)}`
|
|
3025
|
-
};
|
|
3026
|
-
}
|
|
3027
|
-
var ArtifactStore;
|
|
3028
|
-
var init_session_state = __esm({
|
|
3029
|
-
"src/agent/session-state.ts"() {
|
|
3030
|
-
"use strict";
|
|
3031
|
-
ArtifactStore = class {
|
|
3032
|
-
artifacts = /* @__PURE__ */ new Map();
|
|
3033
|
-
maxArtifacts;
|
|
3034
|
-
maxTotalChars;
|
|
3035
|
-
constructor(opts2) {
|
|
3036
|
-
this.maxArtifacts = opts2?.maxArtifacts ?? 200;
|
|
3037
|
-
this.maxTotalChars = opts2?.maxTotalChars ?? 5e5;
|
|
3038
|
-
}
|
|
3039
|
-
add(a) {
|
|
3040
|
-
while (this.totalChars() + a.raw.length > this.maxTotalChars && this.artifacts.size > 0) {
|
|
3041
|
-
this.evictSizeWeighted();
|
|
3042
|
-
}
|
|
3043
|
-
while (this.artifacts.size >= this.maxArtifacts) {
|
|
3044
|
-
this.evictOldest();
|
|
3045
|
-
}
|
|
3046
|
-
this.artifacts.set(a.id, a);
|
|
3047
|
-
}
|
|
3048
|
-
get(id) {
|
|
3049
|
-
return this.artifacts.get(id);
|
|
3050
|
-
}
|
|
3051
|
-
has(id) {
|
|
3052
|
-
return this.artifacts.has(id);
|
|
3053
|
-
}
|
|
3054
|
-
list() {
|
|
3055
|
-
return [...this.artifacts.values()].sort((a, b) => a.ts < b.ts ? -1 : 1);
|
|
3056
|
-
}
|
|
3057
|
-
recall(ids) {
|
|
3058
|
-
const out = [];
|
|
3059
|
-
for (const id of ids) {
|
|
3060
|
-
const a = this.artifacts.get(id);
|
|
3061
|
-
if (a) out.push({ id, artifact: a });
|
|
3062
|
-
}
|
|
3063
|
-
return out;
|
|
3064
|
-
}
|
|
3065
|
-
size() {
|
|
3066
|
-
return this.artifacts.size;
|
|
3067
|
-
}
|
|
3068
|
-
totalChars() {
|
|
3069
|
-
let sum = 0;
|
|
3070
|
-
for (const a of this.artifacts.values()) {
|
|
3071
|
-
sum += a.raw.length;
|
|
3072
|
-
}
|
|
3073
|
-
return sum;
|
|
3074
|
-
}
|
|
3075
|
-
evictOldest() {
|
|
3076
|
-
let oldest;
|
|
3077
|
-
for (const a of this.artifacts.values()) {
|
|
3078
|
-
if (!oldest || a.ts < oldest.ts) oldest = a;
|
|
3079
|
-
}
|
|
3080
|
-
if (oldest) this.artifacts.delete(oldest.id);
|
|
3081
|
-
}
|
|
3082
|
-
/** Evict the largest artifact among the oldest quartile (by timestamp).
|
|
3083
|
-
* Bounded by the oldest quartile so we never evict freshly-added artifacts;
|
|
3084
|
-
* size-weighted within that window so one big artifact gets dropped instead
|
|
3085
|
-
* of many small ones. */
|
|
3086
|
-
evictSizeWeighted() {
|
|
3087
|
-
const sorted = [...this.artifacts.values()].sort((a, b) => a.ts < b.ts ? -1 : 1);
|
|
3088
|
-
if (sorted.length === 0) return;
|
|
3089
|
-
const quartile = Math.max(1, Math.ceil(sorted.length / 4));
|
|
3090
|
-
const candidates = sorted.slice(0, quartile);
|
|
3091
|
-
let pick3 = candidates[0];
|
|
3092
|
-
for (const a of candidates) {
|
|
3093
|
-
if (a.raw.length > pick3.raw.length) pick3 = a;
|
|
3094
|
-
}
|
|
3095
|
-
this.artifacts.delete(pick3.id);
|
|
3096
|
-
}
|
|
3097
|
-
};
|
|
3098
|
-
}
|
|
3099
|
-
});
|
|
3100
|
-
|
|
3101
|
-
// src/agent/artifact-compaction.ts
|
|
3102
|
-
function approxTokens2(n) {
|
|
3103
|
-
return Math.round(n / 3.5);
|
|
3104
|
-
}
|
|
3105
|
-
function estimateMessageTokens(m) {
|
|
3106
|
-
let chars = 0;
|
|
3107
|
-
if (typeof m.content === "string") {
|
|
3108
|
-
chars = m.content.length;
|
|
3109
|
-
} else if (Array.isArray(m.content)) {
|
|
3110
|
-
chars = m.content.map((p) => p.type === "text" ? p.text.length : 0).reduce((a, b) => a + b, 0);
|
|
3111
|
-
}
|
|
3112
|
-
if (m.reasoning_content) chars += m.reasoning_content.length;
|
|
3113
|
-
if (m.tool_calls) {
|
|
3114
|
-
for (const tc of m.tool_calls) {
|
|
3115
|
-
chars += tc.function.name.length + tc.function.arguments.length;
|
|
3116
|
-
}
|
|
3117
|
-
}
|
|
3118
|
-
return approxTokens2(chars);
|
|
3119
|
-
}
|
|
3120
|
-
function estimatePromptTokens(messages) {
|
|
3121
|
-
return messages.reduce((sum, m) => sum + estimateMessageTokens(m), 0);
|
|
3122
|
-
}
|
|
3123
|
-
function groupIntoTurns(messages) {
|
|
3124
|
-
const prefix = [];
|
|
3125
|
-
let i = 0;
|
|
3126
|
-
while (i < messages.length && messages[i].role === "system") {
|
|
3127
|
-
prefix.push(messages[i]);
|
|
3128
|
-
i++;
|
|
3129
|
-
}
|
|
3130
|
-
const turns = [];
|
|
3131
|
-
while (i < messages.length) {
|
|
3132
|
-
if (messages[i].role !== "user") {
|
|
3133
|
-
i++;
|
|
3134
|
-
continue;
|
|
3135
|
-
}
|
|
3136
|
-
const user = messages[i];
|
|
3137
|
-
i++;
|
|
3138
|
-
if (i >= messages.length || messages[i].role !== "assistant") {
|
|
3139
|
-
continue;
|
|
3140
|
-
}
|
|
3141
|
-
const assistant = messages[i];
|
|
3142
|
-
i++;
|
|
3143
|
-
const tools = [];
|
|
3144
|
-
while (i < messages.length && messages[i].role === "tool") {
|
|
3145
|
-
tools.push(messages[i]);
|
|
3146
|
-
i++;
|
|
3147
|
-
}
|
|
3148
|
-
turns.push({ user, assistant, tools });
|
|
3149
|
-
}
|
|
3150
|
-
return { prefix, turns };
|
|
3151
|
-
}
|
|
3152
|
-
function makeArtifactId(type, index) {
|
|
3153
|
-
return `${type}_${Date.now()}_${index}`;
|
|
3154
|
-
}
|
|
3155
|
-
function extractArtifactsFromTurn(turn, startIndex, store) {
|
|
3156
|
-
const artifacts = [];
|
|
3157
|
-
const stateDelta = {
|
|
3158
|
-
files_touched: [],
|
|
3159
|
-
files_modified: [],
|
|
3160
|
-
confirmed_findings: [],
|
|
3161
|
-
recent_failures: [],
|
|
3162
|
-
decisions: [],
|
|
3163
|
-
next_actions: []
|
|
3164
|
-
};
|
|
3165
|
-
const toolCalls = turn.assistant.tool_calls ?? [];
|
|
3166
|
-
for (let ti = 0; ti < turn.tools.length; ti++) {
|
|
3167
|
-
const tm = turn.tools[ti];
|
|
3168
|
-
const tc = toolCalls[ti];
|
|
3169
|
-
const name = tm.name ?? tc?.function.name ?? "unknown";
|
|
3170
|
-
const content = typeof tm.content === "string" ? tm.content : "";
|
|
3171
|
-
let type = "tool_result";
|
|
3172
|
-
let summary = `${name} result`;
|
|
3173
|
-
let path;
|
|
3174
|
-
if (name === "read") {
|
|
3175
|
-
type = "read_slice";
|
|
3176
|
-
try {
|
|
3177
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3178
|
-
path = args.path;
|
|
3179
|
-
summary = `read ${path ?? "file"}`;
|
|
3180
|
-
if (path && !stateDelta.files_touched.includes(path)) stateDelta.files_touched.push(path);
|
|
3181
|
-
} catch {
|
|
3182
|
-
summary = "read file";
|
|
3183
|
-
}
|
|
3184
|
-
} else if (name === "bash") {
|
|
3185
|
-
type = "bash_log";
|
|
3186
|
-
try {
|
|
3187
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3188
|
-
const cmd = args.command ?? "";
|
|
3189
|
-
summary = `bash: ${cmd.slice(0, 60)}`;
|
|
3190
|
-
if (content.includes("Error") || content.includes("error") || content.includes("FAIL")) {
|
|
3191
|
-
stateDelta.recent_failures.push(`bash failed: ${cmd.slice(0, 80)}`);
|
|
3192
|
-
}
|
|
3193
|
-
} catch {
|
|
3194
|
-
summary = "bash command";
|
|
3195
|
-
}
|
|
3196
|
-
} else if (name === "grep") {
|
|
3197
|
-
type = "grep_result";
|
|
3198
|
-
summary = `grep results (${content.split("\n").length} lines)`;
|
|
3199
|
-
} else if (name === "web_fetch") {
|
|
3200
|
-
type = "web_fetch";
|
|
3201
|
-
try {
|
|
3202
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3203
|
-
summary = `web_fetch: ${args.url ?? "url"}`;
|
|
3204
|
-
} catch {
|
|
3205
|
-
summary = "web_fetch";
|
|
3206
|
-
}
|
|
3207
|
-
} else if (name === "write" || name === "edit") {
|
|
3208
|
-
try {
|
|
3209
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3210
|
-
path = args.path;
|
|
3211
|
-
if (path && !stateDelta.files_modified.includes(path)) stateDelta.files_modified.push(path);
|
|
3212
|
-
if (path && !stateDelta.files_touched.includes(path)) stateDelta.files_touched.push(path);
|
|
3213
|
-
} catch {
|
|
3214
|
-
}
|
|
3215
|
-
continue;
|
|
3216
|
-
} else if (name === "glob") {
|
|
3217
|
-
try {
|
|
3218
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3219
|
-
summary = `glob: ${args.pattern ?? ""}`;
|
|
3220
|
-
} catch {
|
|
3221
|
-
summary = "glob";
|
|
3222
|
-
}
|
|
3223
|
-
} else if (name === "tasks_set") {
|
|
3224
|
-
try {
|
|
3225
|
-
const args = tc ? JSON.parse(tc.function.arguments) : {};
|
|
3226
|
-
const tasks = args.tasks ?? [];
|
|
3227
|
-
const inProgress = tasks.filter((t) => t.status === "in_progress").map((t) => t.title);
|
|
3228
|
-
const pending = tasks.filter((t) => t.status === "pending").map((t) => t.title);
|
|
3229
|
-
if (inProgress.length) stateDelta.next_actions.push(...inProgress);
|
|
3230
|
-
if (pending.length) stateDelta.next_actions.push(...pending);
|
|
3231
|
-
summary = `tasks_set: ${tasks.length} tasks`;
|
|
3232
|
-
} catch {
|
|
3233
|
-
summary = "tasks_set";
|
|
3234
|
-
}
|
|
3280
|
+
return a.runtime === runtime2 ? -1 : 1;
|
|
3281
|
+
} else if (a.abi !== b.abi) {
|
|
3282
|
+
return a.abi ? -1 : 1;
|
|
3283
|
+
} else if (a.specificity !== b.specificity) {
|
|
3284
|
+
return a.specificity > b.specificity ? -1 : 1;
|
|
3285
|
+
} else {
|
|
3286
|
+
return 0;
|
|
3287
|
+
}
|
|
3288
|
+
};
|
|
3235
3289
|
}
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
3247
|
-
};
|
|
3248
|
-
artifacts.push(artifact);
|
|
3249
|
-
if (!content.includes("Error") && !content.includes("error") && content.length > 0 && content.length < 2e3) {
|
|
3250
|
-
stateDelta.confirmed_findings.push(`${name}: ${content.slice(0, 200)}`);
|
|
3290
|
+
function isNwjs() {
|
|
3291
|
+
return !!(process.versions && process.versions.nw);
|
|
3292
|
+
}
|
|
3293
|
+
function isElectron() {
|
|
3294
|
+
if (process.versions && process.versions.electron) return true;
|
|
3295
|
+
if (process.env.ELECTRON_RUN_AS_NODE) return true;
|
|
3296
|
+
return typeof window !== "undefined" && window.process && window.process.type === "renderer";
|
|
3297
|
+
}
|
|
3298
|
+
function isAlpine(platform9) {
|
|
3299
|
+
return platform9 === "linux" && fs.existsSync("/etc/alpine-release");
|
|
3251
3300
|
}
|
|
3301
|
+
load.parseTags = parseTags;
|
|
3302
|
+
load.matchTags = matchTags;
|
|
3303
|
+
load.compareTags = compareTags;
|
|
3304
|
+
load.parseTuple = parseTuple;
|
|
3305
|
+
load.matchTuple = matchTuple;
|
|
3306
|
+
load.compareTuples = compareTuples;
|
|
3252
3307
|
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
stateDelta.decisions.push(decision);
|
|
3265
|
-
}
|
|
3266
|
-
}
|
|
3308
|
+
});
|
|
3309
|
+
|
|
3310
|
+
// node_modules/node-gyp-build/index.js
|
|
3311
|
+
var require_node_gyp_build2 = __commonJS({
|
|
3312
|
+
"node_modules/node-gyp-build/index.js"(exports, module) {
|
|
3313
|
+
"use strict";
|
|
3314
|
+
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
3315
|
+
if (typeof runtimeRequire.addon === "function") {
|
|
3316
|
+
module.exports = runtimeRequire.addon.bind(runtimeRequire);
|
|
3317
|
+
} else {
|
|
3318
|
+
module.exports = require_node_gyp_build();
|
|
3267
3319
|
}
|
|
3268
3320
|
}
|
|
3269
|
-
|
|
3321
|
+
});
|
|
3322
|
+
|
|
3323
|
+
// node_modules/isolated-vm/isolated-vm.js
|
|
3324
|
+
var require_isolated_vm = __commonJS({
|
|
3325
|
+
"node_modules/isolated-vm/isolated-vm.js"(exports, module) {
|
|
3326
|
+
"use strict";
|
|
3327
|
+
module.exports = require_node_gyp_build2()(__dirname).ivm;
|
|
3328
|
+
}
|
|
3329
|
+
});
|
|
3330
|
+
|
|
3331
|
+
// src/code-mode/sandbox.ts
|
|
3332
|
+
import { join as join11, dirname as dirname5 } from "path";
|
|
3333
|
+
import { pathToFileURL } from "url";
|
|
3334
|
+
function stripTypescript(code) {
|
|
3335
|
+
let js = code;
|
|
3336
|
+
js = js.replace(/interface\s+\w+\s*\{[\s\S]*?\n\}/g, "");
|
|
3337
|
+
js = js.replace(/type\s+\w+\s*=\s*[^;]+;/g, "");
|
|
3338
|
+
js = js.replace(/(\w+)<[^>]+>(\s*\()/g, "$1$2");
|
|
3339
|
+
js = js.replace(/(\b(?:const|let|var)\s+\w+)\s*:\s*[^=;]+/g, "$1");
|
|
3340
|
+
js = js.replace(/(\(|,\s*)(\w+)\s*:\s*[^,)=]+/g, "$1$2");
|
|
3341
|
+
js = js.replace(/(\)[\s]*)\s*:\s*[^{]+(\s*\{)/g, "$1$2");
|
|
3342
|
+
js = js.replace(/(\)[\s]*)\s*:\s*Promise<[^>]+>(\s*\{)/g, "$1$2");
|
|
3343
|
+
js = js.replace(/\s+as\s+\w+(?:\[\])?/g, "");
|
|
3344
|
+
js = js.replace(/(\w+)(\??)!/g, "$1$2");
|
|
3345
|
+
js = js.replace(/import\s+type\s+[^;]+;/g, "");
|
|
3346
|
+
js = js.replace(/declare\s+[^;]+;/g, "");
|
|
3347
|
+
js = js.replace(/\n{3,}/g, "\n\n");
|
|
3348
|
+
return js.trim();
|
|
3270
3349
|
}
|
|
3271
|
-
function
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3350
|
+
async function loadTypescript(cwd) {
|
|
3351
|
+
try {
|
|
3352
|
+
const tsPath = await import.meta.resolve("typescript");
|
|
3353
|
+
return await import(tsPath);
|
|
3354
|
+
} catch {
|
|
3355
|
+
}
|
|
3356
|
+
let dir = cwd;
|
|
3357
|
+
while (dir !== dirname5(dir)) {
|
|
3358
|
+
try {
|
|
3359
|
+
const tsPath = join11(dir, "node_modules", "typescript", "lib", "typescript.js");
|
|
3360
|
+
return await import(pathToFileURL(tsPath).href);
|
|
3361
|
+
} catch {
|
|
3362
|
+
}
|
|
3363
|
+
dir = dirname5(dir);
|
|
3364
|
+
}
|
|
3365
|
+
return null;
|
|
3366
|
+
}
|
|
3367
|
+
async function transpileOrStrip(code, cwd) {
|
|
3368
|
+
const ts = await loadTypescript(cwd);
|
|
3369
|
+
if (ts) {
|
|
3370
|
+
const result = ts.transpileModule(code, {
|
|
3371
|
+
compilerOptions: {
|
|
3372
|
+
module: ts.ModuleKind.ES2022,
|
|
3373
|
+
target: ts.ScriptTarget.ES2022,
|
|
3374
|
+
esModuleInterop: true,
|
|
3375
|
+
isolatedModules: true
|
|
3376
|
+
}
|
|
3377
|
+
});
|
|
3378
|
+
return { js: result.outputText, warnings: [] };
|
|
3379
|
+
}
|
|
3278
3380
|
return {
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
user_constraints: mergeArr(state.user_constraints, delta.user_constraints),
|
|
3282
|
-
repo_facts: mergeArr(state.repo_facts, delta.repo_facts),
|
|
3283
|
-
files_touched: mergeArr(state.files_touched, delta.files_touched),
|
|
3284
|
-
files_modified: mergeArr(state.files_modified, delta.files_modified),
|
|
3285
|
-
confirmed_findings: mergeArr(state.confirmed_findings, delta.confirmed_findings),
|
|
3286
|
-
open_questions: mergeArr(state.open_questions, delta.open_questions),
|
|
3287
|
-
recent_failures: mergeArr(state.recent_failures, delta.recent_failures),
|
|
3288
|
-
decisions: mergeArr(state.decisions, delta.decisions),
|
|
3289
|
-
next_actions: mergeArr(state.next_actions, delta.next_actions),
|
|
3290
|
-
artifact_index: { ...state.artifact_index, ...delta.artifact_index }
|
|
3381
|
+
js: stripTypescript(code),
|
|
3382
|
+
warnings: ["TypeScript not found in node_modules. Using fallback parser; install typescript for reliable transpilation."]
|
|
3291
3383
|
};
|
|
3292
3384
|
}
|
|
3293
|
-
function
|
|
3294
|
-
const
|
|
3295
|
-
const
|
|
3296
|
-
const
|
|
3297
|
-
const
|
|
3298
|
-
|
|
3385
|
+
async function runWithIsolatedVm(opts2) {
|
|
3386
|
+
const { Isolate } = await Promise.resolve().then(() => __toESM(require_isolated_vm(), 1));
|
|
3387
|
+
const isolate = new Isolate({ memoryLimit: opts2.memoryLimitMB ?? 128 });
|
|
3388
|
+
const context = await isolate.createContext();
|
|
3389
|
+
const jail = context.global;
|
|
3390
|
+
await jail.set("global", jail.derefInto());
|
|
3391
|
+
const logs = [];
|
|
3392
|
+
const toolCalls = [];
|
|
3393
|
+
await context.evalClosure(
|
|
3394
|
+
`globalThis._log = function(...args) {
|
|
3395
|
+
$0.applySync(undefined, [args.map(String).join(" ")], { arguments: { copy: true } });
|
|
3396
|
+
};`,
|
|
3397
|
+
[(msg) => logs.push(msg)],
|
|
3398
|
+
{ arguments: { reference: true } }
|
|
3399
|
+
);
|
|
3400
|
+
await context.eval(`var console = { log: function(...args) { _log(args.map(String).join(" ")); } };`);
|
|
3401
|
+
const toolMap = new Map(opts2.tools.map((t) => [t.name, t]));
|
|
3402
|
+
for (const tool of opts2.tools) {
|
|
3403
|
+
const ref = new (await Promise.resolve().then(() => __toESM(require_isolated_vm(), 1))).Reference(
|
|
3404
|
+
async (argsJson) => {
|
|
3405
|
+
const args = JSON.parse(argsJson);
|
|
3406
|
+
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3407
|
+
const result = await opts2.executor.run(
|
|
3408
|
+
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
3409
|
+
opts2.askPermission,
|
|
3410
|
+
opts2.ctx
|
|
3411
|
+
);
|
|
3412
|
+
toolCalls.push({
|
|
3413
|
+
name: tool.name,
|
|
3414
|
+
args,
|
|
3415
|
+
result: result.content
|
|
3416
|
+
});
|
|
3417
|
+
return result.content;
|
|
3418
|
+
}
|
|
3419
|
+
);
|
|
3420
|
+
await context.evalClosure(
|
|
3421
|
+
`globalThis["_api_${tool.name}"] = function(argsJson) {
|
|
3422
|
+
return $0.applySyncPromise(undefined, [argsJson], { arguments: { copy: true } });
|
|
3423
|
+
};`,
|
|
3424
|
+
[ref],
|
|
3425
|
+
{ arguments: { reference: true } }
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
const apiMethods = opts2.tools.map((t) => ` ${t.name}: function(input) { return _api_${t.name}(JSON.stringify(input ?? {})); }`).join(",\n");
|
|
3429
|
+
await context.eval(`var api = {
|
|
3430
|
+
${apiMethods}
|
|
3431
|
+
};`);
|
|
3432
|
+
const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
|
|
3433
|
+
const wrapped = `(async function() {
|
|
3434
|
+
${jsCode}
|
|
3435
|
+
})();`;
|
|
3436
|
+
try {
|
|
3437
|
+
const timeout = opts2.timeoutMs ?? 3e4;
|
|
3438
|
+
const script = await isolate.compileScript(wrapped);
|
|
3439
|
+
await script.run(context, { timeout, release: true });
|
|
3440
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
3441
|
+
} catch (err) {
|
|
3442
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
3443
|
+
return { output: "", logs, error: message2, toolCalls, warnings };
|
|
3444
|
+
} finally {
|
|
3445
|
+
isolate.dispose();
|
|
3446
|
+
}
|
|
3447
|
+
return { output: logs.join("\n"), logs, toolCalls, warnings };
|
|
3299
3448
|
}
|
|
3300
|
-
function
|
|
3301
|
-
const
|
|
3302
|
-
const
|
|
3303
|
-
const
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
metrics: {
|
|
3309
|
-
estimatedTokensBefore: tokensBefore,
|
|
3310
|
-
estimatedTokensAfter: tokensBefore,
|
|
3311
|
-
archivedArtifacts: 0,
|
|
3312
|
-
recalledArtifacts: 0,
|
|
3313
|
-
rawTurnsRemoved: 0,
|
|
3314
|
-
rawTurnsKept: turns.length
|
|
3449
|
+
async function runWithNodeVm(opts2) {
|
|
3450
|
+
const { runInNewContext } = await import("vm");
|
|
3451
|
+
const logs = [];
|
|
3452
|
+
const toolCalls = [];
|
|
3453
|
+
const sandbox = {
|
|
3454
|
+
console: {
|
|
3455
|
+
log: (...args) => {
|
|
3456
|
+
logs.push(args.map(String).join(" "));
|
|
3315
3457
|
}
|
|
3458
|
+
},
|
|
3459
|
+
api: {},
|
|
3460
|
+
setTimeout,
|
|
3461
|
+
clearTimeout,
|
|
3462
|
+
setInterval,
|
|
3463
|
+
clearInterval,
|
|
3464
|
+
Promise,
|
|
3465
|
+
JSON,
|
|
3466
|
+
Math,
|
|
3467
|
+
Date,
|
|
3468
|
+
Array,
|
|
3469
|
+
Object,
|
|
3470
|
+
String,
|
|
3471
|
+
Number,
|
|
3472
|
+
Boolean,
|
|
3473
|
+
RegExp,
|
|
3474
|
+
Error,
|
|
3475
|
+
TypeError,
|
|
3476
|
+
RangeError,
|
|
3477
|
+
SyntaxError,
|
|
3478
|
+
ReferenceError,
|
|
3479
|
+
Map,
|
|
3480
|
+
Set,
|
|
3481
|
+
WeakMap,
|
|
3482
|
+
WeakSet,
|
|
3483
|
+
Symbol,
|
|
3484
|
+
parseInt,
|
|
3485
|
+
parseFloat,
|
|
3486
|
+
isNaN,
|
|
3487
|
+
isFinite,
|
|
3488
|
+
encodeURI,
|
|
3489
|
+
decodeURI,
|
|
3490
|
+
encodeURIComponent,
|
|
3491
|
+
decodeURIComponent,
|
|
3492
|
+
escape,
|
|
3493
|
+
unescape,
|
|
3494
|
+
Infinity: Infinity,
|
|
3495
|
+
NaN: NaN,
|
|
3496
|
+
undefined: void 0
|
|
3497
|
+
};
|
|
3498
|
+
for (const tool of opts2.tools) {
|
|
3499
|
+
sandbox.api[tool.name] = async (input) => {
|
|
3500
|
+
const args = input ?? {};
|
|
3501
|
+
const toolCallId = `code_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3502
|
+
const result = await opts2.executor.run(
|
|
3503
|
+
{ id: toolCallId, name: tool.name, arguments: JSON.stringify(args) },
|
|
3504
|
+
opts2.askPermission,
|
|
3505
|
+
opts2.ctx
|
|
3506
|
+
);
|
|
3507
|
+
toolCalls.push({
|
|
3508
|
+
name: tool.name,
|
|
3509
|
+
args,
|
|
3510
|
+
result: result.content
|
|
3511
|
+
});
|
|
3512
|
+
return result.content;
|
|
3316
3513
|
};
|
|
3317
3514
|
}
|
|
3318
|
-
const
|
|
3319
|
-
const
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
const
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
summary: artifact.summary,
|
|
3331
|
-
source: artifact.source,
|
|
3332
|
-
path: artifact.path
|
|
3333
|
-
};
|
|
3334
|
-
}
|
|
3335
|
-
newState = mergeState(newState, stateDelta);
|
|
3336
|
-
if (!newState.task && typeof turn.user.content === "string") {
|
|
3337
|
-
newState.task = turn.user.content.slice(0, 200);
|
|
3338
|
-
}
|
|
3339
|
-
}
|
|
3340
|
-
const workingMemory = [];
|
|
3341
|
-
for (const turn of toKeep) {
|
|
3342
|
-
workingMemory.push(turn.user);
|
|
3343
|
-
workingMemory.push(turn.assistant);
|
|
3344
|
-
for (const tm of turn.tools) {
|
|
3345
|
-
workingMemory.push(tm);
|
|
3346
|
-
}
|
|
3515
|
+
const { js: jsCode, warnings } = await transpileOrStrip(opts2.code, opts2.ctx.cwd);
|
|
3516
|
+
const wrapped = `"use strict";
|
|
3517
|
+
(async function() {
|
|
3518
|
+
${jsCode}
|
|
3519
|
+
})();`;
|
|
3520
|
+
try {
|
|
3521
|
+
const timeout = opts2.timeoutMs ?? 3e4;
|
|
3522
|
+
await runInNewContext(wrapped, sandbox, { timeout, displayErrors: true });
|
|
3523
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
3524
|
+
} catch (err) {
|
|
3525
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
3526
|
+
return { output: "", logs, error: message2, toolCalls, warnings };
|
|
3347
3527
|
}
|
|
3348
|
-
|
|
3349
|
-
const newMessages = [...prefix, stateMsg, ...workingMemory];
|
|
3350
|
-
const tokensAfter = estimatePromptTokens(newMessages);
|
|
3351
|
-
const metrics = {
|
|
3352
|
-
estimatedTokensBefore: tokensBefore,
|
|
3353
|
-
estimatedTokensAfter: tokensAfter,
|
|
3354
|
-
archivedArtifacts: archivedCount,
|
|
3355
|
-
recalledArtifacts: 0,
|
|
3356
|
-
rawTurnsRemoved: toCompact.length,
|
|
3357
|
-
rawTurnsKept: toKeep.length
|
|
3358
|
-
};
|
|
3359
|
-
return { newMessages, newState, metrics };
|
|
3528
|
+
return { output: logs.join("\n"), logs, toolCalls, warnings };
|
|
3360
3529
|
}
|
|
3361
|
-
function
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3530
|
+
function buildFallbackWarning(errMessage) {
|
|
3531
|
+
let reason;
|
|
3532
|
+
let fix;
|
|
3533
|
+
if (errMessage.includes("Cannot find module") || errMessage.includes("isolated-vm")) {
|
|
3534
|
+
reason = "The optional dependency `isolated-vm` is not installed.";
|
|
3535
|
+
fix = "Run `npm install isolated-vm` in your project (or `npm install -g isolated-vm` if KimiFlare is installed globally).";
|
|
3536
|
+
} else if (errMessage.includes("bindings") || errMessage.includes(".node")) {
|
|
3537
|
+
reason = "The `isolated-vm` native bindings are incompatible with this Node version or architecture.";
|
|
3538
|
+
fix = "Try `npm rebuild isolated-vm`, or switch to Node 22 LTS if you're on Apple Silicon.";
|
|
3539
|
+
} else {
|
|
3540
|
+
reason = "The secure sandbox (`isolated-vm`) could not be loaded.";
|
|
3541
|
+
fix = "Ensure build tools are installed, then run `npm install isolated-vm`.";
|
|
3368
3542
|
}
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3543
|
+
return `Code Mode is using the built-in Node.js sandbox. Tool execution works normally, but without memory limits or full process isolation. ${reason} ${fix}`;
|
|
3544
|
+
}
|
|
3545
|
+
async function runInSandbox(opts2) {
|
|
3546
|
+
try {
|
|
3547
|
+
return await runWithIsolatedVm(opts2);
|
|
3548
|
+
} catch (err) {
|
|
3549
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
3550
|
+
const result = await runWithNodeVm(opts2);
|
|
3551
|
+
const sessionKey = opts2.ctx.sessionId ?? NO_SESSION_KEY;
|
|
3552
|
+
if (!fallbackWarningShownSessions.has(sessionKey)) {
|
|
3553
|
+
fallbackWarningShownSessions.add(sessionKey);
|
|
3554
|
+
const warning = buildFallbackWarning(message2);
|
|
3555
|
+
return { ...result, warnings: [warning, ...result.warnings ?? []] };
|
|
3378
3556
|
}
|
|
3557
|
+
return result;
|
|
3379
3558
|
}
|
|
3380
|
-
const uniqueIds = [...new Set(ids)].slice(0, 5);
|
|
3381
|
-
const recalled = store.recall(uniqueIds);
|
|
3382
|
-
return { ids: uniqueIds, recalled };
|
|
3383
3559
|
}
|
|
3384
|
-
var
|
|
3385
|
-
|
|
3560
|
+
var fallbackWarningShownSessions, NO_SESSION_KEY;
|
|
3561
|
+
var init_sandbox = __esm({
|
|
3562
|
+
"src/code-mode/sandbox.ts"() {
|
|
3386
3563
|
"use strict";
|
|
3387
|
-
|
|
3564
|
+
fallbackWarningShownSessions = /* @__PURE__ */ new Set();
|
|
3565
|
+
NO_SESSION_KEY = "__no_session__";
|
|
3566
|
+
}
|
|
3567
|
+
});
|
|
3568
|
+
|
|
3569
|
+
// src/code-mode/index.ts
|
|
3570
|
+
var init_code_mode = __esm({
|
|
3571
|
+
"src/code-mode/index.ts"() {
|
|
3572
|
+
"use strict";
|
|
3573
|
+
init_api_generator();
|
|
3574
|
+
init_sandbox();
|
|
3388
3575
|
}
|
|
3389
3576
|
});
|
|
3390
3577
|
|
|
@@ -3987,12 +4174,12 @@ var init_mode = __esm({
|
|
|
3987
4174
|
});
|
|
3988
4175
|
|
|
3989
4176
|
// src/agent/system-prompt.ts
|
|
3990
|
-
import { platform, release, homedir as
|
|
3991
|
-
import { basename, join as
|
|
4177
|
+
import { platform, release, homedir as homedir7 } from "os";
|
|
4178
|
+
import { basename, join as join12 } from "path";
|
|
3992
4179
|
import { readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
3993
4180
|
function loadContextFile(cwd) {
|
|
3994
4181
|
for (const name of CONTEXT_FILENAMES) {
|
|
3995
|
-
const path =
|
|
4182
|
+
const path = join12(cwd, name);
|
|
3996
4183
|
try {
|
|
3997
4184
|
const s = statSync2(path);
|
|
3998
4185
|
if (!s.isFile() || s.size > MAX_CONTEXT_BYTES) continue;
|
|
@@ -4042,7 +4229,7 @@ If the user asks what model you are, answer with exactly: \`${opts2.model}\`. Th
|
|
|
4042
4229
|
- Working directory: ${opts2.cwd}
|
|
4043
4230
|
- Platform: ${platform()} ${release()}
|
|
4044
4231
|
- Shell: ${shell}
|
|
4045
|
-
- Home: ${
|
|
4232
|
+
- Home: ${homedir7()}
|
|
4046
4233
|
- Today: ${date}`;
|
|
4047
4234
|
const hasLsp = opts2.tools.some((t) => t.name.startsWith("lsp_"));
|
|
4048
4235
|
const lspBlock = hasLsp ? "\n\nLSP tools are available for semantic code intelligence. Prefer `lsp_definition` over `grep` when looking for the source of a symbol. Prefer `lsp_references` over `grep` when finding usages. Use `lsp_hover` to confirm types before refactoring." : "";
|
|
@@ -4118,6 +4305,9 @@ function getSessionWebFetchHistory(sessionId) {
|
|
|
4118
4305
|
function isHighSignalMemory(memory) {
|
|
4119
4306
|
return memory.topicKey === "project_dependencies" || memory.topicKey === "project_tsconfig" || memory.topicKey === "project_entry_point" || memory.category === "instruction" || memory.category === "preference" || memory.category === "event" && memory.importance >= 3;
|
|
4120
4307
|
}
|
|
4308
|
+
function codeModeRedirectMessage(tool) {
|
|
4309
|
+
return `Code Mode is on: \`${tool}\` is not available as a direct tool because its full output would flood your context. Call \`api.${tool}({ ... })\` INSIDE an \`execute_code\` block instead \u2014 only what you \`console.log\` is returned to you. You can batch several reads/greps/commands in a single execute_code call.`;
|
|
4310
|
+
}
|
|
4121
4311
|
function extractLastUserText(messages) {
|
|
4122
4312
|
const lastUser = [...messages].reverse().find((m) => m.role === "user");
|
|
4123
4313
|
if (!lastUser) return "";
|
|
@@ -4162,7 +4352,7 @@ async function runAgentTurn(opts2) {
|
|
|
4162
4352
|
const lastUserPrompt = extractLastUserText(opts2.messages);
|
|
4163
4353
|
const userPromptPreview = lastUserPrompt.slice(0, 200);
|
|
4164
4354
|
const skipSkillRouting = opts2.intentClassification?.tier === "light" && lastUserPrompt.length < 40;
|
|
4165
|
-
const recallPromise = opts2.sessionStartRecall && opts2.memoryManager ? (async () => {
|
|
4355
|
+
const recallPromise = opts2.sessionStartRecall && opts2.memoryManager && !hasRecalledMemory(opts2.messages) ? (async () => {
|
|
4166
4356
|
const results = await opts2.sessionStartRecall;
|
|
4167
4357
|
if (results.length === 0 || !opts2.memoryManager) return null;
|
|
4168
4358
|
const text = await opts2.memoryManager.synthesizeRecalled(results, opts2.signal);
|
|
@@ -4193,11 +4383,10 @@ async function runAgentTurn(opts2) {
|
|
|
4193
4383
|
}
|
|
4194
4384
|
if (recallSettled.status === "fulfilled" && recallSettled.value) {
|
|
4195
4385
|
const { text, count } = recallSettled.value;
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
opts2.callbacks.onMemoryRecalled?.(count);
|
|
4386
|
+
if (injectRecalledMemoryOnce(opts2.messages, text)) {
|
|
4387
|
+
memoryRecalledCount = count;
|
|
4388
|
+
opts2.callbacks.onMemoryRecalled?.(count);
|
|
4389
|
+
}
|
|
4201
4390
|
}
|
|
4202
4391
|
if (skillsSettled.status === "fulfilled" && skillsSettled.value) {
|
|
4203
4392
|
skillResult = skillsSettled.value;
|
|
@@ -4257,7 +4446,9 @@ async function runAgentTurn(opts2) {
|
|
|
4257
4446
|
Available APIs:
|
|
4258
4447
|
${codeModeApiString}
|
|
4259
4448
|
|
|
4260
|
-
Use console.log() to return results. Only console.log output
|
|
4449
|
+
Use console.log() to return results. Only console.log output is sent back to you.
|
|
4450
|
+
|
|
4451
|
+
IMPORTANT \u2014 explore through code, not direct tools: to read files, run shell commands, grep, or glob, call api.read(...), api.bash(...), api.grep(...), api.glob(...) INSIDE this code block and console.log only what you need. Do NOT call read/bash/grep/glob as separate tools \u2014 their full output floods your context, while here only what you log returns. Batch multiple reads/greps/commands into a single execute_code call.`,
|
|
4261
4452
|
parameters: {
|
|
4262
4453
|
type: "object",
|
|
4263
4454
|
properties: {
|
|
@@ -4286,6 +4477,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
4286
4477
|
const LOOP_THRESHOLD = 2;
|
|
4287
4478
|
const webFetchHistory = getSessionWebFetchHistory(opts2.sessionId);
|
|
4288
4479
|
let webFetchesThisTurn = 0;
|
|
4480
|
+
let codeModeRedirects = 0;
|
|
4289
4481
|
const MAX_WEB_FETCH_PER_TURN = 5;
|
|
4290
4482
|
const WEB_FETCH_DOMAIN_THRESHOLD = 2;
|
|
4291
4483
|
let cumulativePromptTokens = 0;
|
|
@@ -4542,6 +4734,16 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
4542
4734
|
});
|
|
4543
4735
|
continue;
|
|
4544
4736
|
}
|
|
4737
|
+
if (codeMode && CODE_MODE_REDIRECT_TOOLS.has(tc.function.name) && codeModeRedirects < MAX_CODE_MODE_REDIRECTS) {
|
|
4738
|
+
codeModeRedirects++;
|
|
4739
|
+
items.push({
|
|
4740
|
+
kind: "blocked",
|
|
4741
|
+
tc,
|
|
4742
|
+
loopSignature,
|
|
4743
|
+
result: { tool_call_id: tc.id, name: tc.function.name, content: codeModeRedirectMessage(tc.function.name), ok: false }
|
|
4744
|
+
});
|
|
4745
|
+
continue;
|
|
4746
|
+
}
|
|
4545
4747
|
if (tc.function.name === "web_fetch") {
|
|
4546
4748
|
const args = JSON.parse(tc.function.arguments || "{}");
|
|
4547
4749
|
const url = args.url || "";
|
|
@@ -4906,6 +5108,13 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
4906
5108
|
opts2.callbacks.onToolResult?.(result);
|
|
4907
5109
|
recentToolCalls.push(loopSignature);
|
|
4908
5110
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
5111
|
+
} else if (codeMode && CODE_MODE_REDIRECT_TOOLS.has(tc.function.name) && codeModeRedirects < MAX_CODE_MODE_REDIRECTS) {
|
|
5112
|
+
codeModeRedirects++;
|
|
5113
|
+
const msg = codeModeRedirectMessage(tc.function.name);
|
|
5114
|
+
const redirectResult = { tool_call_id: tc.id, name: tc.function.name, content: msg, ok: false };
|
|
5115
|
+
toolResults.push(redirectResult);
|
|
5116
|
+
opts2.messages.push({ role: "tool", tool_call_id: tc.id, content: msg, name: tc.function.name });
|
|
5117
|
+
opts2.callbacks.onToolResult?.(redirectResult);
|
|
4909
5118
|
} else {
|
|
4910
5119
|
opts2.callbacks.onToolWillExecute?.(tc.id, tc.function.name);
|
|
4911
5120
|
logger.debug("turn:tool_start", { sessionId: opts2.sessionId, tool: tc.function.name, toolCallId: tc.id });
|
|
@@ -5142,13 +5351,14 @@ function validateToolArguments(raw) {
|
|
|
5142
5351
|
return "{}";
|
|
5143
5352
|
}
|
|
5144
5353
|
}
|
|
5145
|
-
var BudgetExhaustedError, AgentLoopError, codeModeApiCache, driftEvents, DRIFT_WINDOW, DRIFT_THRESHOLD, memoryExtractionErrorCounts, sessionWebFetchHistory, SESSION_WEB_FETCH_CAP, DEFAULT_MAX_COMPLETION_TOKENS, BUDGET_SAFETY_MARGIN_TOKENS, MAX_TOOL_CONTENT_CHARS;
|
|
5354
|
+
var BudgetExhaustedError, AgentLoopError, codeModeApiCache, driftEvents, DRIFT_WINDOW, DRIFT_THRESHOLD, memoryExtractionErrorCounts, sessionWebFetchHistory, SESSION_WEB_FETCH_CAP, DEFAULT_MAX_COMPLETION_TOKENS, BUDGET_SAFETY_MARGIN_TOKENS, MAX_TOOL_CONTENT_CHARS, CODE_MODE_REDIRECT_TOOLS, MAX_CODE_MODE_REDIRECTS;
|
|
5146
5355
|
var init_loop = __esm({
|
|
5147
5356
|
"src/agent/loop.ts"() {
|
|
5148
5357
|
"use strict";
|
|
5149
5358
|
init_client();
|
|
5150
5359
|
init_registry2();
|
|
5151
5360
|
init_messages();
|
|
5361
|
+
init_recall_inject();
|
|
5152
5362
|
init_cost_debug();
|
|
5153
5363
|
init_extractors();
|
|
5154
5364
|
init_strip_reasoning();
|
|
@@ -5180,6 +5390,8 @@ var init_loop = __esm({
|
|
|
5180
5390
|
DEFAULT_MAX_COMPLETION_TOKENS = 16384;
|
|
5181
5391
|
BUDGET_SAFETY_MARGIN_TOKENS = 8192;
|
|
5182
5392
|
MAX_TOOL_CONTENT_CHARS = 1e4;
|
|
5393
|
+
CODE_MODE_REDIRECT_TOOLS = /* @__PURE__ */ new Set(["read", "bash", "grep", "glob"]);
|
|
5394
|
+
MAX_CODE_MODE_REDIRECTS = 4;
|
|
5183
5395
|
}
|
|
5184
5396
|
});
|
|
5185
5397
|
|
|
@@ -5243,10 +5455,10 @@ var init_tool_error = __esm({
|
|
|
5243
5455
|
|
|
5244
5456
|
// src/util/paths.ts
|
|
5245
5457
|
import { resolve, isAbsolute, relative, sep } from "path";
|
|
5246
|
-
import { homedir as
|
|
5458
|
+
import { homedir as homedir8 } from "os";
|
|
5247
5459
|
function resolvePath(cwd, input) {
|
|
5248
5460
|
if (input.startsWith("~/") || input === "~") {
|
|
5249
|
-
return resolve(
|
|
5461
|
+
return resolve(homedir8(), input === "~" ? "." : input.slice(2));
|
|
5250
5462
|
}
|
|
5251
5463
|
return isAbsolute(input) ? input : resolve(cwd, input);
|
|
5252
5464
|
}
|
|
@@ -5473,7 +5685,7 @@ var init_edit = __esm({
|
|
|
5473
5685
|
// src/tools/bash.ts
|
|
5474
5686
|
import { spawn } from "child_process";
|
|
5475
5687
|
import { tmpdir, platform as platform2 } from "os";
|
|
5476
|
-
import { join as
|
|
5688
|
+
import { join as join13 } from "path";
|
|
5477
5689
|
function getShellCommand(override) {
|
|
5478
5690
|
const raw = override?.trim();
|
|
5479
5691
|
if (raw && raw !== "auto") {
|
|
@@ -5519,7 +5731,7 @@ function injectCoauthor(command, coauthor) {
|
|
|
5519
5731
|
const mentionsGit = /\bgit\b/.test(trimmed);
|
|
5520
5732
|
if (!createsCommit && !isRebaseContinue && !mentionsGit) return command;
|
|
5521
5733
|
if (movesHeadOnly) return command;
|
|
5522
|
-
const tmpFile =
|
|
5734
|
+
const tmpFile = join13(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
5523
5735
|
const amendBlock = `
|
|
5524
5736
|
if ! git log -1 --pretty=%B 2>/dev/null | grep -qF "${trailer}"; then
|
|
5525
5737
|
git log -1 --pretty=%B | git interpret-trailers --trailer "${trailer}" > "${tmpFile}" && git commit --amend -F "${tmpFile}" --no-edit && rm -f "${tmpFile}"
|
|
@@ -5635,7 +5847,7 @@ var init_bash = __esm({
|
|
|
5635
5847
|
|
|
5636
5848
|
// src/util/glob.ts
|
|
5637
5849
|
import { readdir as readdir3, lstat, realpath } from "fs/promises";
|
|
5638
|
-
import { join as
|
|
5850
|
+
import { join as join14, relative as relative2, resolve as resolve2 } from "path";
|
|
5639
5851
|
function parsePattern(pattern) {
|
|
5640
5852
|
const parts = pattern.split(/\//g);
|
|
5641
5853
|
return parts.map((p) => {
|
|
@@ -5744,7 +5956,7 @@ async function* walk(root, pattern, options) {
|
|
|
5744
5956
|
if (!dot && name.startsWith(".")) continue;
|
|
5745
5957
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
5746
5958
|
if (!matched) continue;
|
|
5747
|
-
const childPath =
|
|
5959
|
+
const childPath = join14(dirPath, name);
|
|
5748
5960
|
const childRel = [...relativeParts, name];
|
|
5749
5961
|
const childRelStr = childRel.join("/");
|
|
5750
5962
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -5769,7 +5981,7 @@ async function* walk(root, pattern, options) {
|
|
|
5769
5981
|
if (!dot && name.startsWith(".")) continue;
|
|
5770
5982
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
5771
5983
|
if (!matched) continue;
|
|
5772
|
-
const childPath =
|
|
5984
|
+
const childPath = join14(dirPath, name);
|
|
5773
5985
|
const childRel = [...relativeParts, name];
|
|
5774
5986
|
const childRelStr = childRel.join("/");
|
|
5775
5987
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -5811,7 +6023,7 @@ async function* walk(root, pattern, options) {
|
|
|
5811
6023
|
const name = String(ent.name);
|
|
5812
6024
|
if (name === "." || name === "..") continue;
|
|
5813
6025
|
if (!dot && name.startsWith(".")) continue;
|
|
5814
|
-
const childPath =
|
|
6026
|
+
const childPath = join14(dirPath, name);
|
|
5815
6027
|
const childRel = [...relativeParts, name];
|
|
5816
6028
|
const childRelStr = childRel.join("/");
|
|
5817
6029
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -6497,7 +6709,7 @@ __export(changelog_image_exports, {
|
|
|
6497
6709
|
});
|
|
6498
6710
|
import { readFile as readFile9 } from "fs/promises";
|
|
6499
6711
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
6500
|
-
import { join as
|
|
6712
|
+
import { join as join15 } from "path";
|
|
6501
6713
|
import { Resvg } from "@resvg/resvg-js";
|
|
6502
6714
|
async function githubFetch2(path, token) {
|
|
6503
6715
|
const controller = new AbortController();
|
|
@@ -6529,7 +6741,7 @@ function escapeXml(str) {
|
|
|
6529
6741
|
}
|
|
6530
6742
|
async function loadLogoBase64() {
|
|
6531
6743
|
try {
|
|
6532
|
-
const buf = await readFile9(
|
|
6744
|
+
const buf = await readFile9(join15(process.cwd(), "docs", "logo.png"));
|
|
6533
6745
|
return `data:image/png;base64,${buf.toString("base64")}`;
|
|
6534
6746
|
} catch {
|
|
6535
6747
|
return null;
|
|
@@ -6837,7 +7049,7 @@ Format your response as plain text bullet points, one per line, starting with "\
|
|
|
6837
7049
|
// src/tools/browser.ts
|
|
6838
7050
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
6839
7051
|
import { tmpdir as tmpdir2 } from "os";
|
|
6840
|
-
import { join as
|
|
7052
|
+
import { join as join16, dirname as dirname7 } from "path";
|
|
6841
7053
|
async function autoScroll(page) {
|
|
6842
7054
|
await page.evaluate(async () => {
|
|
6843
7055
|
await new Promise((resolve8) => {
|
|
@@ -6913,7 +7125,7 @@ var init_browser = __esm({
|
|
|
6913
7125
|
}
|
|
6914
7126
|
let screenshotPath;
|
|
6915
7127
|
if (args.screenshot) {
|
|
6916
|
-
screenshotPath =
|
|
7128
|
+
screenshotPath = join16(tmpdir2(), `kimiflare-browser-${Date.now()}.png`);
|
|
6917
7129
|
await mkdir7(dirname7(screenshotPath), { recursive: true });
|
|
6918
7130
|
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
6919
7131
|
}
|
|
@@ -8295,11 +8507,11 @@ __export(sessions_exports, {
|
|
|
8295
8507
|
sessionsDir: () => sessionsDir
|
|
8296
8508
|
});
|
|
8297
8509
|
import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir8, readdir as readdir4, stat as stat4 } from "fs/promises";
|
|
8298
|
-
import { homedir as
|
|
8299
|
-
import { join as
|
|
8510
|
+
import { homedir as homedir9 } from "os";
|
|
8511
|
+
import { join as join17 } from "path";
|
|
8300
8512
|
function sessionsDir() {
|
|
8301
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
8302
|
-
return
|
|
8513
|
+
const xdg = process.env.XDG_DATA_HOME || join17(homedir9(), ".local", "share");
|
|
8514
|
+
return join17(xdg, "kimiflare", "sessions");
|
|
8303
8515
|
}
|
|
8304
8516
|
function sanitize(text) {
|
|
8305
8517
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -8319,7 +8531,7 @@ function makeSessionId(firstPrompt) {
|
|
|
8319
8531
|
async function saveSession(file) {
|
|
8320
8532
|
const dir = sessionsDir();
|
|
8321
8533
|
await mkdir8(dir, { recursive: true });
|
|
8322
|
-
const path =
|
|
8534
|
+
const path = join17(dir, `${file.id}.json`);
|
|
8323
8535
|
await writeFile9(path, JSON.stringify(file, null, 2), "utf8");
|
|
8324
8536
|
return path;
|
|
8325
8537
|
}
|
|
@@ -8339,7 +8551,7 @@ async function listSessions(limit = 30, cwd) {
|
|
|
8339
8551
|
const summaries = [];
|
|
8340
8552
|
for (const name of entries) {
|
|
8341
8553
|
if (!name.endsWith(".json")) continue;
|
|
8342
|
-
const path =
|
|
8554
|
+
const path = join17(dir, name);
|
|
8343
8555
|
try {
|
|
8344
8556
|
const [s, raw] = await Promise.all([stat4(path), readFile10(path, "utf8")]);
|
|
8345
8557
|
const parsed = JSON.parse(raw);
|
|
@@ -8450,7 +8662,7 @@ var init_image = __esm({
|
|
|
8450
8662
|
|
|
8451
8663
|
// src/permissions-evaluator.ts
|
|
8452
8664
|
import { resolve as resolve3, relative as relative3 } from "path";
|
|
8453
|
-
import { homedir as
|
|
8665
|
+
import { homedir as homedir10 } from "os";
|
|
8454
8666
|
function evaluatePermissionRules(req, rules) {
|
|
8455
8667
|
const toolRules = rules[req.tool];
|
|
8456
8668
|
if (!toolRules) return "ask";
|
|
@@ -8466,7 +8678,7 @@ function evaluatePermissionRules(req, rules) {
|
|
|
8466
8678
|
}
|
|
8467
8679
|
function expandHome(path) {
|
|
8468
8680
|
if (path.startsWith("~/")) {
|
|
8469
|
-
return resolve3(
|
|
8681
|
+
return resolve3(homedir10(), path.slice(2));
|
|
8470
8682
|
}
|
|
8471
8683
|
return path;
|
|
8472
8684
|
}
|
|
@@ -8492,7 +8704,7 @@ function extractTarget(tool, args, cwd) {
|
|
|
8492
8704
|
function matchPattern(target, pattern, cwd) {
|
|
8493
8705
|
let expandedPattern = pattern;
|
|
8494
8706
|
if (pattern.startsWith("~/")) {
|
|
8495
|
-
expandedPattern = resolve3(
|
|
8707
|
+
expandedPattern = resolve3(homedir10(), pattern.slice(2));
|
|
8496
8708
|
}
|
|
8497
8709
|
if (target.startsWith(expandedPattern)) {
|
|
8498
8710
|
return true;
|
|
@@ -8539,16 +8751,16 @@ var init_types = __esm({
|
|
|
8539
8751
|
});
|
|
8540
8752
|
|
|
8541
8753
|
// src/hooks/settings.ts
|
|
8542
|
-
import { existsSync as existsSync2, readFileSync as readFileSync3, mkdirSync as
|
|
8543
|
-
import { homedir as
|
|
8544
|
-
import { join as
|
|
8754
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
8755
|
+
import { homedir as homedir11 } from "os";
|
|
8756
|
+
import { join as join18, dirname as dirname8 } from "path";
|
|
8545
8757
|
import { createHash } from "crypto";
|
|
8546
8758
|
function globalSettingsPath() {
|
|
8547
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
8548
|
-
return
|
|
8759
|
+
const xdg = process.env.XDG_CONFIG_HOME || join18(homedir11(), ".config");
|
|
8760
|
+
return join18(xdg, "kimiflare", "settings.json");
|
|
8549
8761
|
}
|
|
8550
8762
|
function projectSettingsPath(cwd) {
|
|
8551
|
-
return
|
|
8763
|
+
return join18(cwd, ".kimiflare", "settings.json");
|
|
8552
8764
|
}
|
|
8553
8765
|
function readSettingsFile(path) {
|
|
8554
8766
|
if (!existsSync2(path)) return null;
|
|
@@ -8624,8 +8836,8 @@ function appendHook(scope, cwd, event, hook) {
|
|
|
8624
8836
|
return rest;
|
|
8625
8837
|
});
|
|
8626
8838
|
existing.hooks = hooks;
|
|
8627
|
-
|
|
8628
|
-
|
|
8839
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
8840
|
+
writeFileSync2(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
8629
8841
|
return path;
|
|
8630
8842
|
}
|
|
8631
8843
|
function setHookEnabled(cwd, id, enabled) {
|
|
@@ -8650,8 +8862,8 @@ function setHookEnabled(cwd, id, enabled) {
|
|
|
8650
8862
|
}
|
|
8651
8863
|
}
|
|
8652
8864
|
if (changed) {
|
|
8653
|
-
|
|
8654
|
-
|
|
8865
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
8866
|
+
writeFileSync2(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
8655
8867
|
return path;
|
|
8656
8868
|
}
|
|
8657
8869
|
void scope;
|
|
@@ -9381,11 +9593,11 @@ var init_heuristic = __esm({
|
|
|
9381
9593
|
|
|
9382
9594
|
// src/cost-attribution/classify-from-session.ts
|
|
9383
9595
|
import { readFile as readFile13 } from "fs/promises";
|
|
9384
|
-
import { join as
|
|
9385
|
-
import { homedir as
|
|
9596
|
+
import { join as join19 } from "path";
|
|
9597
|
+
import { homedir as homedir12 } from "os";
|
|
9386
9598
|
function sessionsDir2() {
|
|
9387
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
9388
|
-
return
|
|
9599
|
+
const xdg = process.env.XDG_DATA_HOME || join19(homedir12(), ".local", "share");
|
|
9600
|
+
return join19(xdg, "kimiflare", "sessions");
|
|
9389
9601
|
}
|
|
9390
9602
|
function parseToolCalls(calls) {
|
|
9391
9603
|
return calls.map((c) => {
|
|
@@ -9399,7 +9611,7 @@ function parseToolCalls(calls) {
|
|
|
9399
9611
|
}
|
|
9400
9612
|
async function classifyFromSessionFile(sessionId) {
|
|
9401
9613
|
try {
|
|
9402
|
-
const raw = await readFile13(
|
|
9614
|
+
const raw = await readFile13(join19(sessionsDir2(), `${sessionId}.json`), "utf8");
|
|
9403
9615
|
const session = JSON.parse(raw);
|
|
9404
9616
|
const messages = session.messages ?? [];
|
|
9405
9617
|
const turns = [];
|
|
@@ -9433,14 +9645,14 @@ __export(cli_exports, {
|
|
|
9433
9645
|
runCostCommand: () => runCostCommand
|
|
9434
9646
|
});
|
|
9435
9647
|
import { readFile as readFile14 } from "fs/promises";
|
|
9436
|
-
import { join as
|
|
9437
|
-
import { homedir as
|
|
9648
|
+
import { join as join20 } from "path";
|
|
9649
|
+
import { homedir as homedir13 } from "os";
|
|
9438
9650
|
function usageDir() {
|
|
9439
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
9440
|
-
return
|
|
9651
|
+
const xdg = process.env.XDG_DATA_HOME || join20(homedir13(), ".local", "share");
|
|
9652
|
+
return join20(xdg, "kimiflare");
|
|
9441
9653
|
}
|
|
9442
9654
|
function usagePath() {
|
|
9443
|
-
return
|
|
9655
|
+
return join20(usageDir(), "usage.json");
|
|
9444
9656
|
}
|
|
9445
9657
|
function today() {
|
|
9446
9658
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -10442,7 +10654,7 @@ __export(db_exports, {
|
|
|
10442
10654
|
});
|
|
10443
10655
|
import Database from "better-sqlite3";
|
|
10444
10656
|
import { dirname as dirname9 } from "path";
|
|
10445
|
-
import { mkdirSync as
|
|
10657
|
+
import { mkdirSync as mkdirSync4, statSync as statSync3 } from "fs";
|
|
10446
10658
|
function initSchema(db) {
|
|
10447
10659
|
db.exec(`
|
|
10448
10660
|
CREATE TABLE IF NOT EXISTS memories (
|
|
@@ -10526,7 +10738,7 @@ function openMemoryDb(dbPath) {
|
|
|
10526
10738
|
if (dbInstance) {
|
|
10527
10739
|
dbInstance.close();
|
|
10528
10740
|
}
|
|
10529
|
-
|
|
10741
|
+
mkdirSync4(dirname9(dbPath), { recursive: true });
|
|
10530
10742
|
dbInstance = new Database(dbPath);
|
|
10531
10743
|
dbInstance.pragma("journal_mode = WAL");
|
|
10532
10744
|
dbInstance.pragma("foreign_keys = ON");
|
|
@@ -11237,6 +11449,50 @@ Return a JSON array of strings. Example:
|
|
|
11237
11449
|
}
|
|
11238
11450
|
return { id: memory.id, superseded: supersededIds.length > 0 ? supersededIds : void 0 };
|
|
11239
11451
|
}
|
|
11452
|
+
/**
|
|
11453
|
+
* Store a plan directly under a deterministic topic key.
|
|
11454
|
+
* Skips embedding, verification, and hypothetical queries so it is fast and
|
|
11455
|
+
* deterministic. Supersedes any previous plan stored under the same key.
|
|
11456
|
+
*/
|
|
11457
|
+
async rememberPlan(plan, repoPath, sessionId, topicKey = "current_dev_plan") {
|
|
11458
|
+
if (!this.db) throw new Error("Memory DB not open");
|
|
11459
|
+
const safeContent = this.shouldRedact() ? redactSecrets(plan) : plan;
|
|
11460
|
+
if (!safeContent.trim()) {
|
|
11461
|
+
throw new Error("Plan content is empty after redaction");
|
|
11462
|
+
}
|
|
11463
|
+
const normalizedKey = topicKey.trim();
|
|
11464
|
+
if (!normalizedKey) {
|
|
11465
|
+
throw new Error("Plan topic key cannot be empty");
|
|
11466
|
+
}
|
|
11467
|
+
const supersededIds = [];
|
|
11468
|
+
const existing = findMemoriesByTopicKey(this.db, repoPath, normalizedKey);
|
|
11469
|
+
for (const old of existing) {
|
|
11470
|
+
supersedeMemory(this.db, old.id, "pending");
|
|
11471
|
+
supersededIds.push(old.id);
|
|
11472
|
+
}
|
|
11473
|
+
const zeroEmbedding = new Float32Array(DEFAULT_EMBEDDING_DIM);
|
|
11474
|
+
const memory = insertMemory(this.db, {
|
|
11475
|
+
content: safeContent,
|
|
11476
|
+
category: "task",
|
|
11477
|
+
sourceSessionId: sessionId,
|
|
11478
|
+
repoPath,
|
|
11479
|
+
importance: 4,
|
|
11480
|
+
topicKey: normalizedKey
|
|
11481
|
+
}, zeroEmbedding);
|
|
11482
|
+
for (const oldId of supersededIds) {
|
|
11483
|
+
supersedeMemory(this.db, oldId, memory.id);
|
|
11484
|
+
}
|
|
11485
|
+
return { id: memory.id, superseded: supersededIds.length > 0 ? supersededIds : void 0 };
|
|
11486
|
+
}
|
|
11487
|
+
/**
|
|
11488
|
+
* Recall the latest memory for an exact topic key.
|
|
11489
|
+
* Does not use embeddings; returns null if no matching memory exists.
|
|
11490
|
+
*/
|
|
11491
|
+
getByTopicKey(repoPath, topicKey) {
|
|
11492
|
+
if (!this.db) return null;
|
|
11493
|
+
const rows = findMemoriesByTopicKey(this.db, repoPath, topicKey);
|
|
11494
|
+
return rows[0] ?? null;
|
|
11495
|
+
}
|
|
11240
11496
|
/**
|
|
11241
11497
|
* Count high-signal memories created since the given timestamp.
|
|
11242
11498
|
* Used for KIMI.md drift detection (Trigger A: session-start check).
|
|
@@ -12471,19 +12727,19 @@ var init_pricing = __esm({
|
|
|
12471
12727
|
|
|
12472
12728
|
// src/usage-tracker.ts
|
|
12473
12729
|
import { readFile as readFile16, writeFile as writeFile10, mkdir as mkdir9 } from "fs/promises";
|
|
12474
|
-
import { homedir as
|
|
12475
|
-
import { join as
|
|
12730
|
+
import { homedir as homedir14 } from "os";
|
|
12731
|
+
import { join as join22 } from "path";
|
|
12476
12732
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
12477
12733
|
import { randomUUID } from "crypto";
|
|
12478
12734
|
function usageDir2() {
|
|
12479
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
12480
|
-
return
|
|
12735
|
+
const xdg = process.env.XDG_DATA_HOME || join22(homedir14(), ".local", "share");
|
|
12736
|
+
return join22(xdg, "kimiflare");
|
|
12481
12737
|
}
|
|
12482
12738
|
function usagePath2() {
|
|
12483
|
-
return
|
|
12739
|
+
return join22(usageDir2(), "usage.json");
|
|
12484
12740
|
}
|
|
12485
12741
|
function historyPath() {
|
|
12486
|
-
return
|
|
12742
|
+
return join22(usageDir2(), "history.jsonl");
|
|
12487
12743
|
}
|
|
12488
12744
|
function today2() {
|
|
12489
12745
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -12930,8 +13186,8 @@ var init_permissions = __esm({
|
|
|
12930
13186
|
|
|
12931
13187
|
// src/sdk/session.ts
|
|
12932
13188
|
import { resolve as resolve6 } from "path";
|
|
12933
|
-
import { homedir as
|
|
12934
|
-
import { join as
|
|
13189
|
+
import { homedir as homedir15 } from "os";
|
|
13190
|
+
import { join as join23 } from "path";
|
|
12935
13191
|
import { existsSync as existsSync3 } from "fs";
|
|
12936
13192
|
async function createAgentSession(opts2) {
|
|
12937
13193
|
const config2 = await resolveSdkConfig(opts2);
|
|
@@ -12946,7 +13202,7 @@ async function createAgentSession(opts2) {
|
|
|
12946
13202
|
let memoryManager = null;
|
|
12947
13203
|
const memoryEnabled = opts2.memoryEnabled ?? config2.memoryEnabled ?? false;
|
|
12948
13204
|
if (memoryEnabled) {
|
|
12949
|
-
const dbPath = config2.memoryDbPath ??
|
|
13205
|
+
const dbPath = config2.memoryDbPath ?? join23(homedir15(), ".local", "share", "kimiflare", "memory.db");
|
|
12950
13206
|
memoryManager = new MemoryManager({
|
|
12951
13207
|
dbPath,
|
|
12952
13208
|
accountId: config2.accountId,
|
|
@@ -12977,7 +13233,7 @@ async function createAgentSession(opts2) {
|
|
|
12977
13233
|
}
|
|
12978
13234
|
let sessionFile;
|
|
12979
13235
|
if (opts2.sessionId) {
|
|
12980
|
-
const filePath =
|
|
13236
|
+
const filePath = join23(sessionsDir(), `${opts2.sessionId}.json`);
|
|
12981
13237
|
try {
|
|
12982
13238
|
sessionFile = await loadSession(filePath);
|
|
12983
13239
|
} catch {
|
|
@@ -13390,7 +13646,7 @@ var init_session = __esm({
|
|
|
13390
13646
|
}
|
|
13391
13647
|
}
|
|
13392
13648
|
});
|
|
13393
|
-
if (existsSync3(
|
|
13649
|
+
if (existsSync3(join23(this.cwd, "KIMI.md"))) {
|
|
13394
13650
|
this.messages[0] = {
|
|
13395
13651
|
role: "system",
|
|
13396
13652
|
content: buildSystemPrompt({
|
|
@@ -13667,7 +13923,7 @@ var init_repo_info = __esm({
|
|
|
13667
13923
|
// src/agent/supervisor.ts
|
|
13668
13924
|
import { readdir as readdir5, readFile as readFile17, stat as stat5 } from "fs/promises";
|
|
13669
13925
|
import { createHash as createHash2 } from "crypto";
|
|
13670
|
-
import { resolve as resolve7, join as
|
|
13926
|
+
import { resolve as resolve7, join as join24 } from "path";
|
|
13671
13927
|
async function preReadFilesForWorkers(files, repoRoot, maxChars = DEFAULT_PRE_READ_MAX_CHARS) {
|
|
13672
13928
|
const results = [];
|
|
13673
13929
|
const filesRead = [];
|
|
@@ -13702,7 +13958,7 @@ ${results.join("\n\n")}`,
|
|
|
13702
13958
|
}
|
|
13703
13959
|
function getPreReadFilesFromMemory(cfg, repoRoot, limit = 10) {
|
|
13704
13960
|
if (!cfg.memoryEnabled) return [];
|
|
13705
|
-
const dbPath = cfg.memoryDbPath ??
|
|
13961
|
+
const dbPath = cfg.memoryDbPath ?? join24(repoRoot, ".kimiflare", "memory.db");
|
|
13706
13962
|
try {
|
|
13707
13963
|
const db = openMemoryDb(dbPath);
|
|
13708
13964
|
const files = getTopRelatedFiles(db, repoRoot, limit);
|
|
@@ -15203,7 +15459,7 @@ var init_attach_mode = __esm({
|
|
|
15203
15459
|
import { spawn as spawn4 } from "child_process";
|
|
15204
15460
|
import { mkdtemp, readFile as readFile18, writeFile as writeFile11, rm } from "fs/promises";
|
|
15205
15461
|
import { tmpdir as tmpdir3 } from "os";
|
|
15206
|
-
import { join as
|
|
15462
|
+
import { join as join25 } from "path";
|
|
15207
15463
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
15208
15464
|
async function cfApiFetch(accountId, apiToken, path, init) {
|
|
15209
15465
|
const url = `${CF_API}/accounts/${encodeURIComponent(accountId)}${path}`;
|
|
@@ -15434,8 +15690,8 @@ ${wranglerInstall.stderr.slice(-600)}`,
|
|
|
15434
15690
|
ok: true
|
|
15435
15691
|
};
|
|
15436
15692
|
yield { message: "Prerequisites ready", ok: true };
|
|
15437
|
-
const tmpRoot = await mkdtemp(
|
|
15438
|
-
const repoDir =
|
|
15693
|
+
const tmpRoot = await mkdtemp(join25(tmpdir3(), "kimiflare-commute-"));
|
|
15694
|
+
const repoDir = join25(tmpRoot, "kimiflare-commute");
|
|
15439
15695
|
yield { message: `Fetching worker source from GitHub (${COMMUTE_REPO})\u2026` };
|
|
15440
15696
|
const clone = await runCmd("git", ["clone", "--depth", "1", "--branch", COMMUTE_BRANCH, COMMUTE_REPO, repoDir], { timeoutMs: 6e4 });
|
|
15441
15697
|
if (clone.code !== 0) {
|
|
@@ -15444,8 +15700,8 @@ ${(clone.stderr || clone.stdout).slice(0, 400)}`, error: true };
|
|
|
15444
15700
|
throw new Error("clone failed");
|
|
15445
15701
|
}
|
|
15446
15702
|
yield { message: "Source fetched from GitHub", ok: true };
|
|
15447
|
-
const workerDir =
|
|
15448
|
-
const wranglerToml =
|
|
15703
|
+
const workerDir = join25(repoDir, "remote", "worker");
|
|
15704
|
+
const wranglerToml = join25(workerDir, "wrangler.toml");
|
|
15449
15705
|
yield { message: "Installing Worker dependencies (npm install)\u2026" };
|
|
15450
15706
|
const install = await runCmd("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], {
|
|
15451
15707
|
cwd: workerDir,
|
|
@@ -15787,7 +16043,7 @@ __export(app_helpers_exports, {
|
|
|
15787
16043
|
});
|
|
15788
16044
|
import { execSync as execSync3, spawn as spawn5 } from "child_process";
|
|
15789
16045
|
import { existsSync as existsSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
15790
|
-
import { join as
|
|
16046
|
+
import { join as join26 } from "path";
|
|
15791
16047
|
import { platform as platform3 } from "os";
|
|
15792
16048
|
function buildFilePickerIgnoreList(cwd) {
|
|
15793
16049
|
const hardcoded = [
|
|
@@ -15859,7 +16115,7 @@ function buildFilePickerIgnoreList(cwd) {
|
|
|
15859
16115
|
];
|
|
15860
16116
|
const gitignorePatterns = [];
|
|
15861
16117
|
try {
|
|
15862
|
-
const gitignorePath =
|
|
16118
|
+
const gitignorePath = join26(cwd, ".gitignore");
|
|
15863
16119
|
const stats = statSync4(gitignorePath);
|
|
15864
16120
|
if (stats.size > MAX_GITIGNORE_SIZE) {
|
|
15865
16121
|
return hardcoded;
|
|
@@ -16405,7 +16661,7 @@ var init_frontmatter = __esm({
|
|
|
16405
16661
|
|
|
16406
16662
|
// src/skills/loader.ts
|
|
16407
16663
|
import { readFile as readFile19, readdir as readdir6, stat as stat6 } from "fs/promises";
|
|
16408
|
-
import { join as
|
|
16664
|
+
import { join as join27, extname } from "path";
|
|
16409
16665
|
function normalizeManifest(raw, filePath) {
|
|
16410
16666
|
const name = typeof raw.name === "string" ? raw.name : "";
|
|
16411
16667
|
const description = typeof raw.description === "string" ? raw.description : "";
|
|
@@ -16441,7 +16697,7 @@ async function loadSkillsFromDir(dirPath) {
|
|
|
16441
16697
|
const entries = await readdir6(dirPath);
|
|
16442
16698
|
const files = [];
|
|
16443
16699
|
for (const entry of entries) {
|
|
16444
|
-
const full =
|
|
16700
|
+
const full = join27(dirPath, entry);
|
|
16445
16701
|
const s = await stat6(full);
|
|
16446
16702
|
if (s.isFile() && extname(entry) === ".md") {
|
|
16447
16703
|
files.push(full);
|
|
@@ -16470,7 +16726,7 @@ var init_loader = __esm({
|
|
|
16470
16726
|
|
|
16471
16727
|
// src/skills/discovery.ts
|
|
16472
16728
|
import { readdir as readdir7, stat as stat7, readFile as readFile20 } from "fs/promises";
|
|
16473
|
-
import { join as
|
|
16729
|
+
import { join as join28, extname as extname2 } from "path";
|
|
16474
16730
|
async function dirExists(path) {
|
|
16475
16731
|
try {
|
|
16476
16732
|
const s = await stat7(path);
|
|
@@ -16494,15 +16750,15 @@ async function scanSkillDir(dirPath, source) {
|
|
|
16494
16750
|
for (const entry of entries) {
|
|
16495
16751
|
if (!entry.isFile()) continue;
|
|
16496
16752
|
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
16497
|
-
files.push({ filePath:
|
|
16753
|
+
files.push({ filePath: join28(dirPath, entry.name), source });
|
|
16498
16754
|
}
|
|
16499
16755
|
return files;
|
|
16500
16756
|
}
|
|
16501
16757
|
async function discoverSkills(cwd) {
|
|
16502
|
-
const agentsSkills = await scanSkillDir(
|
|
16503
|
-
const agentsMd = await fileExists(
|
|
16504
|
-
const githubSkills = await scanSkillDir(
|
|
16505
|
-
const kimiflareSkills = await scanSkillDir(
|
|
16758
|
+
const agentsSkills = await scanSkillDir(join28(cwd, ".agents", "skills"), "agents");
|
|
16759
|
+
const agentsMd = await fileExists(join28(cwd, "AGENTS.md")) ? [{ filePath: join28(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
16760
|
+
const githubSkills = await scanSkillDir(join28(cwd, ".github", "skills"), "github");
|
|
16761
|
+
const kimiflareSkills = await scanSkillDir(join28(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
16506
16762
|
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
16507
16763
|
return ordered;
|
|
16508
16764
|
}
|
|
@@ -16823,6 +17079,32 @@ var init_distill = __esm({
|
|
|
16823
17079
|
}
|
|
16824
17080
|
});
|
|
16825
17081
|
|
|
17082
|
+
// src/agent/plan-resolver.ts
|
|
17083
|
+
function resolvePlanForFresh(opts2) {
|
|
17084
|
+
const { mode, messages, sessionPlan, memoryManager, memoryEnabled, repoPath } = opts2;
|
|
17085
|
+
if (mode !== "plan") {
|
|
17086
|
+
return null;
|
|
17087
|
+
}
|
|
17088
|
+
if (sessionPlan) {
|
|
17089
|
+
return sessionPlan;
|
|
17090
|
+
}
|
|
17091
|
+
if (memoryEnabled && memoryManager) {
|
|
17092
|
+
const stored = memoryManager.getByTopicKey(repoPath, PLAN_MEMORY_TOPIC_KEY);
|
|
17093
|
+
if (stored?.content) {
|
|
17094
|
+
return stored.content;
|
|
17095
|
+
}
|
|
17096
|
+
}
|
|
17097
|
+
return distillSessionPlan(messages);
|
|
17098
|
+
}
|
|
17099
|
+
var PLAN_MEMORY_TOPIC_KEY;
|
|
17100
|
+
var init_plan_resolver = __esm({
|
|
17101
|
+
"src/agent/plan-resolver.ts"() {
|
|
17102
|
+
"use strict";
|
|
17103
|
+
init_distill();
|
|
17104
|
+
PLAN_MEMORY_TOPIC_KEY = "current_dev_plan";
|
|
17105
|
+
}
|
|
17106
|
+
});
|
|
17107
|
+
|
|
16826
17108
|
// src/agent/continuation-summary.ts
|
|
16827
17109
|
import { execSync as execSync4 } from "child_process";
|
|
16828
17110
|
function extractFirstUserGoal(messages) {
|
|
@@ -18015,11 +18297,11 @@ var init_ai_gateway_api = __esm({
|
|
|
18015
18297
|
|
|
18016
18298
|
// src/skills/manager.ts
|
|
18017
18299
|
import { mkdir as mkdir10, writeFile as writeFile12, unlink as unlink2, readFile as readFile21 } from "fs/promises";
|
|
18018
|
-
import { join as
|
|
18300
|
+
import { join as join29 } from "path";
|
|
18019
18301
|
function getSkillDirs(cwd) {
|
|
18020
18302
|
return {
|
|
18021
|
-
projectDir:
|
|
18022
|
-
globalDir:
|
|
18303
|
+
projectDir: join29(cwd, ".kimiflare", "skills"),
|
|
18304
|
+
globalDir: join29(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
18023
18305
|
};
|
|
18024
18306
|
}
|
|
18025
18307
|
async function listAllSkills(cwd) {
|
|
@@ -18033,7 +18315,7 @@ async function listAllSkills(cwd) {
|
|
|
18033
18315
|
async function createSkill(opts2) {
|
|
18034
18316
|
const dirs = getSkillDirs(opts2.cwd);
|
|
18035
18317
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
18036
|
-
const filepath =
|
|
18318
|
+
const filepath = join29(dir, `${opts2.name}.md`);
|
|
18037
18319
|
const frontmatter = {
|
|
18038
18320
|
name: opts2.name,
|
|
18039
18321
|
enabled: true,
|
|
@@ -18153,14 +18435,14 @@ var init_frontmatter2 = __esm({
|
|
|
18153
18435
|
|
|
18154
18436
|
// src/commands/loader.ts
|
|
18155
18437
|
import { open, realpath as realpath2 } from "fs/promises";
|
|
18156
|
-
import { homedir as
|
|
18157
|
-
import { join as
|
|
18438
|
+
import { homedir as homedir16 } from "os";
|
|
18439
|
+
import { join as join30, relative as relative6, sep as sep2 } from "path";
|
|
18158
18440
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
18159
|
-
return
|
|
18441
|
+
return join30(cwd, ".kimiflare", "commands");
|
|
18160
18442
|
}
|
|
18161
18443
|
function globalCommandsDir() {
|
|
18162
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
18163
|
-
return
|
|
18444
|
+
const xdg = process.env.XDG_CONFIG_HOME || join30(homedir16(), ".config");
|
|
18445
|
+
return join30(xdg, "kimiflare", "commands");
|
|
18164
18446
|
}
|
|
18165
18447
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
18166
18448
|
const warnings = [];
|
|
@@ -18531,12 +18813,12 @@ var init_recommended = __esm({
|
|
|
18531
18813
|
|
|
18532
18814
|
// src/init/context-generator.ts
|
|
18533
18815
|
import { existsSync as existsSync5, statSync as statSync5 } from "fs";
|
|
18534
|
-
import { join as
|
|
18816
|
+
import { join as join31 } from "path";
|
|
18535
18817
|
function detectFlavor(cwd) {
|
|
18536
18818
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
18537
18819
|
if (flavor === "generic") continue;
|
|
18538
18820
|
for (const sig of signatures) {
|
|
18539
|
-
const path =
|
|
18821
|
+
const path = join31(cwd, sig);
|
|
18540
18822
|
if (sig.includes("*")) {
|
|
18541
18823
|
try {
|
|
18542
18824
|
const parts = sig.split("*");
|
|
@@ -18557,14 +18839,14 @@ function detectFlavor(cwd) {
|
|
|
18557
18839
|
}
|
|
18558
18840
|
function findFile(cwd, candidates) {
|
|
18559
18841
|
for (const c of candidates) {
|
|
18560
|
-
if (existsSync5(
|
|
18842
|
+
if (existsSync5(join31(cwd, c))) return c;
|
|
18561
18843
|
}
|
|
18562
18844
|
return null;
|
|
18563
18845
|
}
|
|
18564
18846
|
function findSourceRoots(cwd) {
|
|
18565
18847
|
const roots = [];
|
|
18566
18848
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
18567
|
-
const p =
|
|
18849
|
+
const p = join31(cwd, r);
|
|
18568
18850
|
try {
|
|
18569
18851
|
const s = statSync5(p);
|
|
18570
18852
|
if (s.isDirectory()) roots.push(r);
|
|
@@ -18575,9 +18857,9 @@ function findSourceRoots(cwd) {
|
|
|
18575
18857
|
}
|
|
18576
18858
|
function findCiConfig(cwd) {
|
|
18577
18859
|
for (const c of CI_PATHS) {
|
|
18578
|
-
if (existsSync5(
|
|
18860
|
+
if (existsSync5(join31(cwd, c))) {
|
|
18579
18861
|
try {
|
|
18580
|
-
const s = statSync5(
|
|
18862
|
+
const s = statSync5(join31(cwd, c));
|
|
18581
18863
|
return s.isDirectory() ? c : c;
|
|
18582
18864
|
} catch {
|
|
18583
18865
|
}
|
|
@@ -18714,7 +18996,7 @@ function analyzeProject(cwd) {
|
|
|
18714
18996
|
ciConfig: findCiConfig(cwd),
|
|
18715
18997
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
18716
18998
|
sourceRoots: findSourceRoots(cwd),
|
|
18717
|
-
hasGit: existsSync5(
|
|
18999
|
+
hasGit: existsSync5(join31(cwd, ".git"))
|
|
18718
19000
|
};
|
|
18719
19001
|
}
|
|
18720
19002
|
function bashDiscoveryCommands(profile) {
|
|
@@ -18879,7 +19161,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
|
|
|
18879
19161
|
}
|
|
18880
19162
|
function buildInitPrompt(cwd) {
|
|
18881
19163
|
const existingName = ["KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
18882
|
-
(n) => existsSync5(
|
|
19164
|
+
(n) => existsSync5(join31(cwd, n))
|
|
18883
19165
|
);
|
|
18884
19166
|
const isRefresh = existingName !== void 0;
|
|
18885
19167
|
const targetFilename = existingName ?? "KIMI.md";
|
|
@@ -18968,10 +19250,10 @@ __export(ui_mode_exports, {
|
|
|
18968
19250
|
runUiMode: () => runUiMode
|
|
18969
19251
|
});
|
|
18970
19252
|
import { execSync as execSync6, spawn as spawn6 } from "child_process";
|
|
18971
|
-
import { appendFileSync, mkdirSync as
|
|
19253
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, openSync } from "fs";
|
|
18972
19254
|
import { unlink as unlink4 } from "fs/promises";
|
|
18973
|
-
import { join as
|
|
18974
|
-
import { homedir as
|
|
19255
|
+
import { join as join32 } from "path";
|
|
19256
|
+
import { homedir as homedir17, platform as platform6 } from "os";
|
|
18975
19257
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
18976
19258
|
import { readFile as readFile22 } from "fs/promises";
|
|
18977
19259
|
import QRCode from "qrcode";
|
|
@@ -18979,7 +19261,7 @@ function kimiLog(payload) {
|
|
|
18979
19261
|
if (!KIMI_LOG_PATH) return;
|
|
18980
19262
|
try {
|
|
18981
19263
|
const line = JSON.stringify({ ts: Date.now() / 1e3, ...payload }) + "\n";
|
|
18982
|
-
|
|
19264
|
+
appendFileSync2(KIMI_LOG_PATH, line);
|
|
18983
19265
|
} catch {
|
|
18984
19266
|
}
|
|
18985
19267
|
}
|
|
@@ -19011,13 +19293,13 @@ function gatewayFromOpts2(opts2) {
|
|
|
19011
19293
|
}
|
|
19012
19294
|
async function runUiMode(opts2) {
|
|
19013
19295
|
await loadCamouflage();
|
|
19014
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ||
|
|
19015
|
-
const camoDbDir =
|
|
19296
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || join32(homedir17(), ".config");
|
|
19297
|
+
const camoDbDir = join32(xdgConfig, "kimiflare");
|
|
19016
19298
|
try {
|
|
19017
|
-
|
|
19299
|
+
mkdirSync5(camoDbDir, { recursive: true });
|
|
19018
19300
|
} catch {
|
|
19019
19301
|
}
|
|
19020
|
-
const camoDbPath =
|
|
19302
|
+
const camoDbPath = join32(camoDbDir, "camouflage-sessions.db");
|
|
19021
19303
|
let cam;
|
|
19022
19304
|
try {
|
|
19023
19305
|
cam = await mount({
|
|
@@ -19073,7 +19355,7 @@ ${err instanceof Error ? err.message : err}`);
|
|
|
19073
19355
|
let mcpInit = false;
|
|
19074
19356
|
let lspInit = false;
|
|
19075
19357
|
if (startupCfg?.memoryEnabled) {
|
|
19076
|
-
const dbPath = startupCfg.memoryDbPath ??
|
|
19358
|
+
const dbPath = startupCfg.memoryDbPath ?? join32(process.cwd(), ".kimiflare", "memory.db");
|
|
19077
19359
|
memoryManager = new MemoryManager({
|
|
19078
19360
|
dbPath,
|
|
19079
19361
|
accountId: opts2.accountId,
|
|
@@ -19099,7 +19381,7 @@ ${err instanceof Error ? err.message : err}`);
|
|
|
19099
19381
|
}
|
|
19100
19382
|
});
|
|
19101
19383
|
}
|
|
19102
|
-
const skillDbPath = startupCfg?.memoryDbPath ??
|
|
19384
|
+
const skillDbPath = startupCfg?.memoryDbPath ?? join32(process.cwd(), ".kimiflare", "memory.db");
|
|
19103
19385
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
19104
19386
|
initSkillsSchema(skillDb);
|
|
19105
19387
|
void indexSkills({
|
|
@@ -19909,6 +20191,10 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
19909
20191
|
const plan = distillSessionPlan(messages);
|
|
19910
20192
|
if (plan) {
|
|
19911
20193
|
sessionPlan = plan;
|
|
20194
|
+
if (startupCfg?.memoryEnabled && memoryManager) {
|
|
20195
|
+
void memoryManager.rememberPlan(plan, process.cwd(), randomUUID2()).catch(() => {
|
|
20196
|
+
});
|
|
20197
|
+
}
|
|
19912
20198
|
}
|
|
19913
20199
|
}
|
|
19914
20200
|
if (planOptionsRef.current && !currentController?.signal.aborted) {
|
|
@@ -21655,7 +21941,14 @@ changelog-image failed: ${err instanceof Error ? err.message : String(err)}
|
|
|
21655
21941
|
return true;
|
|
21656
21942
|
}
|
|
21657
21943
|
void (async () => {
|
|
21658
|
-
const summary =
|
|
21944
|
+
const summary = currentMode === "plan" ? resolvePlanForFresh({
|
|
21945
|
+
mode: currentMode,
|
|
21946
|
+
messages,
|
|
21947
|
+
sessionPlan,
|
|
21948
|
+
memoryManager,
|
|
21949
|
+
memoryEnabled: startupCfg?.memoryEnabled,
|
|
21950
|
+
repoPath: process.cwd()
|
|
21951
|
+
}) : await generateContinuationSummary({
|
|
21659
21952
|
messages,
|
|
21660
21953
|
mode: currentMode,
|
|
21661
21954
|
accountId: opts2.accountId,
|
|
@@ -21954,6 +22247,7 @@ var init_ui_mode = __esm({
|
|
|
21954
22247
|
init_sessions();
|
|
21955
22248
|
init_llm_summarize();
|
|
21956
22249
|
init_distill();
|
|
22250
|
+
init_plan_resolver();
|
|
21957
22251
|
init_continuation_summary();
|
|
21958
22252
|
init_greetings();
|
|
21959
22253
|
init_theme();
|
|
@@ -26731,10 +27025,10 @@ var init_wcag = __esm({
|
|
|
26731
27025
|
|
|
26732
27026
|
// src/ui/theme-loader.ts
|
|
26733
27027
|
import { readFile as readFile23, readdir as readdir9 } from "fs/promises";
|
|
26734
|
-
import { join as
|
|
26735
|
-
import { homedir as
|
|
27028
|
+
import { join as join33 } from "path";
|
|
27029
|
+
import { homedir as homedir18 } from "os";
|
|
26736
27030
|
function projectThemesDir(cwd = process.cwd()) {
|
|
26737
|
-
return
|
|
27031
|
+
return join33(cwd, ".kimiflare", "themes");
|
|
26738
27032
|
}
|
|
26739
27033
|
function isHexColor(c) {
|
|
26740
27034
|
return /^#[0-9a-fA-F]{6}$/.test(c);
|
|
@@ -26823,7 +27117,7 @@ async function loadThemesFromDir(dir, source) {
|
|
|
26823
27117
|
return { themes, errors };
|
|
26824
27118
|
}
|
|
26825
27119
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
26826
|
-
const path =
|
|
27120
|
+
const path = join33(dir, file);
|
|
26827
27121
|
let raw;
|
|
26828
27122
|
try {
|
|
26829
27123
|
raw = await readFile23(path, "utf-8");
|
|
@@ -26972,8 +27266,8 @@ var init_theme_loader = __esm({
|
|
|
26972
27266
|
"use strict";
|
|
26973
27267
|
init_wcag();
|
|
26974
27268
|
init_theme();
|
|
26975
|
-
USER_THEMES_DIR =
|
|
26976
|
-
process.env.XDG_CONFIG_HOME ||
|
|
27269
|
+
USER_THEMES_DIR = join33(
|
|
27270
|
+
process.env.XDG_CONFIG_HOME || join33(homedir18(), ".config"),
|
|
26977
27271
|
"kimiflare",
|
|
26978
27272
|
"themes"
|
|
26979
27273
|
);
|
|
@@ -31078,9 +31372,7 @@ function useSessionManager(deps) {
|
|
|
31078
31372
|
const results = await manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
31079
31373
|
if (results.length > 0) {
|
|
31080
31374
|
const text = await manager.synthesizeRecalled(results);
|
|
31081
|
-
|
|
31082
|
-
const insertIdx = lastSystemIdx >= 0 ? lastSystemIdx + 1 : d.messagesRef.current.length;
|
|
31083
|
-
d.messagesRef.current.splice(insertIdx, 0, { role: "system", content: text });
|
|
31375
|
+
injectRecalledMemoryOnce(d.messagesRef.current, text);
|
|
31084
31376
|
}
|
|
31085
31377
|
} catch {
|
|
31086
31378
|
}
|
|
@@ -31197,6 +31489,7 @@ var init_use_session_manager = __esm({
|
|
|
31197
31489
|
"use strict";
|
|
31198
31490
|
init_sessions();
|
|
31199
31491
|
init_session_state();
|
|
31492
|
+
init_recall_inject();
|
|
31200
31493
|
init_usage_tracker();
|
|
31201
31494
|
init_log_sink();
|
|
31202
31495
|
init_app_helpers();
|
|
@@ -31350,14 +31643,14 @@ __export(tui_report_exports, {
|
|
|
31350
31643
|
getCategoryReportText: () => getCategoryReportText
|
|
31351
31644
|
});
|
|
31352
31645
|
import { readFile as readFile24 } from "fs/promises";
|
|
31353
|
-
import { join as
|
|
31354
|
-
import { homedir as
|
|
31646
|
+
import { join as join34 } from "path";
|
|
31647
|
+
import { homedir as homedir19 } from "os";
|
|
31355
31648
|
function usageDir3() {
|
|
31356
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
31357
|
-
return
|
|
31649
|
+
const xdg = process.env.XDG_DATA_HOME || join34(homedir19(), ".local", "share");
|
|
31650
|
+
return join34(xdg, "kimiflare");
|
|
31358
31651
|
}
|
|
31359
31652
|
function usagePath3() {
|
|
31360
|
-
return
|
|
31653
|
+
return join34(usageDir3(), "usage.json");
|
|
31361
31654
|
}
|
|
31362
31655
|
function today3() {
|
|
31363
31656
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -31426,7 +31719,7 @@ var init_tui_report = __esm({
|
|
|
31426
31719
|
});
|
|
31427
31720
|
|
|
31428
31721
|
// src/ui/slash-commands.ts
|
|
31429
|
-
import { join as
|
|
31722
|
+
import { join as join35 } from "path";
|
|
31430
31723
|
import { unlink as unlink5 } from "fs/promises";
|
|
31431
31724
|
import QRCode2 from "qrcode";
|
|
31432
31725
|
function executeFreshStart(ctx, planText, overrideMode) {
|
|
@@ -31507,6 +31800,7 @@ var init_slash_commands = __esm({
|
|
|
31507
31800
|
init_session_store();
|
|
31508
31801
|
init_deploy();
|
|
31509
31802
|
init_tui_auth();
|
|
31803
|
+
init_plan_resolver();
|
|
31510
31804
|
init_continuation_summary();
|
|
31511
31805
|
init_clipboard();
|
|
31512
31806
|
handleExit = (ctx) => {
|
|
@@ -31559,7 +31853,14 @@ var init_slash_commands = __esm({
|
|
|
31559
31853
|
]);
|
|
31560
31854
|
return true;
|
|
31561
31855
|
}
|
|
31562
|
-
const summary =
|
|
31856
|
+
const summary = ctx.mode === "plan" ? resolvePlanForFresh({
|
|
31857
|
+
mode: ctx.mode,
|
|
31858
|
+
messages: ctx.messagesRef.current,
|
|
31859
|
+
sessionPlan: ctx.sessionPlanRef.current,
|
|
31860
|
+
memoryManager: ctx.memoryManagerRef.current,
|
|
31861
|
+
memoryEnabled: cfg?.memoryEnabled,
|
|
31862
|
+
repoPath: process.cwd()
|
|
31863
|
+
}) : await generateContinuationSummary({
|
|
31563
31864
|
messages: ctx.messagesRef.current,
|
|
31564
31865
|
mode: ctx.mode,
|
|
31565
31866
|
accountId: cfg?.accountId ?? "",
|
|
@@ -32276,7 +32577,7 @@ ${lines.join("\n")}` }]);
|
|
|
32276
32577
|
void (async () => {
|
|
32277
32578
|
try {
|
|
32278
32579
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
32279
|
-
const file = await loadSession(
|
|
32580
|
+
const file = await loadSession(join35(sessionsDir3(), `${currentId}.json`));
|
|
32280
32581
|
const cps = file.checkpoints ?? [];
|
|
32281
32582
|
if (cps.length === 0) {
|
|
32282
32583
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
|
|
@@ -32321,7 +32622,7 @@ ${lines.join("\n")}` }]);
|
|
|
32321
32622
|
try {
|
|
32322
32623
|
ctx.ensureSessionId();
|
|
32323
32624
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
32324
|
-
const filePath =
|
|
32625
|
+
const filePath = join35(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
|
|
32325
32626
|
await addCheckpoint(filePath, cp);
|
|
32326
32627
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
|
|
32327
32628
|
} catch (e) {
|
|
@@ -32956,7 +33257,7 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
32956
33257
|
|
|
32957
33258
|
// src/init/run-init.ts
|
|
32958
33259
|
import { existsSync as existsSync6 } from "fs";
|
|
32959
|
-
import { join as
|
|
33260
|
+
import { join as join36 } from "path";
|
|
32960
33261
|
async function runInit(deps) {
|
|
32961
33262
|
const {
|
|
32962
33263
|
cfg,
|
|
@@ -33159,7 +33460,7 @@ async function runInit(deps) {
|
|
|
33159
33460
|
}
|
|
33160
33461
|
}
|
|
33161
33462
|
});
|
|
33162
|
-
if (existsSync6(
|
|
33463
|
+
if (existsSync6(join36(cwd, "KIMI.md"))) {
|
|
33163
33464
|
if (cacheStableRef.current) {
|
|
33164
33465
|
messagesRef.current[1] = {
|
|
33165
33466
|
role: "system",
|
|
@@ -33254,7 +33555,7 @@ var init_run_init = __esm({
|
|
|
33254
33555
|
|
|
33255
33556
|
// src/ui/run-startup-tasks.ts
|
|
33256
33557
|
import { existsSync as existsSync7 } from "fs";
|
|
33257
|
-
import { join as
|
|
33558
|
+
import { join as join37 } from "path";
|
|
33258
33559
|
function runStartupTasks(deps) {
|
|
33259
33560
|
const {
|
|
33260
33561
|
cfg,
|
|
@@ -33275,7 +33576,7 @@ function runStartupTasks(deps) {
|
|
|
33275
33576
|
}
|
|
33276
33577
|
});
|
|
33277
33578
|
if (cfg.memoryEnabled) {
|
|
33278
|
-
const dbPath = cfg.memoryDbPath ??
|
|
33579
|
+
const dbPath = cfg.memoryDbPath ?? join37(process.cwd(), ".kimiflare", "memory.db");
|
|
33279
33580
|
const manager = new MemoryManager({
|
|
33280
33581
|
dbPath,
|
|
33281
33582
|
accountId: cfg.accountId,
|
|
@@ -33309,7 +33610,7 @@ function runStartupTasks(deps) {
|
|
|
33309
33610
|
});
|
|
33310
33611
|
const cwd = process.cwd();
|
|
33311
33612
|
sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
33312
|
-
if (existsSync7(
|
|
33613
|
+
if (existsSync7(join37(cwd, "KIMI.md"))) {
|
|
33313
33614
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
33314
33615
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
33315
33616
|
if (driftCount >= 5) {
|
|
@@ -33320,7 +33621,7 @@ function runStartupTasks(deps) {
|
|
|
33320
33621
|
memoryManagerRef.current?.close();
|
|
33321
33622
|
memoryManagerRef.current = null;
|
|
33322
33623
|
}
|
|
33323
|
-
const skillDbPath = cfg.memoryDbPath ??
|
|
33624
|
+
const skillDbPath = cfg.memoryDbPath ?? join37(process.cwd(), ".kimiflare", "memory.db");
|
|
33324
33625
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
33325
33626
|
initSkillsSchema(skillDb);
|
|
33326
33627
|
void indexSkills({
|
|
@@ -33784,7 +34085,7 @@ __export(app_exports, {
|
|
|
33784
34085
|
import React25, { useState as useState29, useRef as useRef7, useEffect as useEffect11, useCallback as useCallback10, useMemo as useMemo6 } from "react";
|
|
33785
34086
|
import { Box as Box42, Text as Text43, useApp, useInput as useInput21, render } from "ink";
|
|
33786
34087
|
import { existsSync as existsSync8 } from "fs";
|
|
33787
|
-
import { join as
|
|
34088
|
+
import { join as join38 } from "path";
|
|
33788
34089
|
import { jsx as jsx44, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
33789
34090
|
function App({
|
|
33790
34091
|
initialCfg,
|
|
@@ -34404,18 +34705,17 @@ ${wcagWarnings.join("\n")}` }
|
|
|
34404
34705
|
const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
|
|
34405
34706
|
if (results.length > 0 && !signal.aborted) {
|
|
34406
34707
|
const text = await manager.synthesizeRecalled(results);
|
|
34407
|
-
|
|
34408
|
-
|
|
34409
|
-
|
|
34410
|
-
|
|
34411
|
-
|
|
34412
|
-
|
|
34413
|
-
|
|
34414
|
-
|
|
34415
|
-
|
|
34416
|
-
|
|
34417
|
-
|
|
34418
|
-
await saveSessionSafe();
|
|
34708
|
+
if (injectRecalledMemoryOnce(result.newMessages, text)) {
|
|
34709
|
+
setEvents((e) => [
|
|
34710
|
+
...e,
|
|
34711
|
+
{
|
|
34712
|
+
kind: "memory",
|
|
34713
|
+
key: mkKey(),
|
|
34714
|
+
text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
|
|
34715
|
+
}
|
|
34716
|
+
]);
|
|
34717
|
+
await saveSessionSafe();
|
|
34718
|
+
}
|
|
34419
34719
|
}
|
|
34420
34720
|
} catch {
|
|
34421
34721
|
}
|
|
@@ -34999,7 +35299,14 @@ ${wcagWarnings.join("\n")}` }
|
|
|
34999
35299
|
(picked) => {
|
|
35000
35300
|
setShowPlanCompletePicker(false);
|
|
35001
35301
|
if (!picked || picked === "continue") return;
|
|
35002
|
-
const plan =
|
|
35302
|
+
const plan = resolvePlanForFresh({
|
|
35303
|
+
mode: "plan",
|
|
35304
|
+
messages: messagesRef.current,
|
|
35305
|
+
sessionPlan: sessionPlanRef.current,
|
|
35306
|
+
memoryManager: memoryManagerRef.current,
|
|
35307
|
+
memoryEnabled: cfg?.memoryEnabled,
|
|
35308
|
+
repoPath: process.cwd()
|
|
35309
|
+
});
|
|
35003
35310
|
if (!plan) {
|
|
35004
35311
|
setEvents((e) => [
|
|
35005
35312
|
...e,
|
|
@@ -35199,7 +35506,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
35199
35506
|
}
|
|
35200
35507
|
}
|
|
35201
35508
|
turnCounterRef.current += 1;
|
|
35202
|
-
if (turnCounterRef.current % 15 === 0 && existsSync8(
|
|
35509
|
+
if (turnCounterRef.current % 15 === 0 && existsSync8(join38(process.cwd(), "KIMI.md")) && !kimiMdStale) {
|
|
35203
35510
|
setEvents((e) => [
|
|
35204
35511
|
...e,
|
|
35205
35512
|
{ kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps KimiFlare stay accurate as your project evolves." }
|
|
@@ -35223,7 +35530,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
35223
35530
|
};
|
|
35224
35531
|
ensureSessionId();
|
|
35225
35532
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
35226
|
-
const filePath =
|
|
35533
|
+
const filePath = join38(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
35227
35534
|
await addCheckpoint(filePath, cp);
|
|
35228
35535
|
}
|
|
35229
35536
|
const summary = await generateContinuationSummary({
|
|
@@ -35679,18 +35986,17 @@ ${conflicts.join("\n")}` }
|
|
|
35679
35986
|
const results = await manager.recall({ text: queryText, repoPath: cwd, limit: 5 });
|
|
35680
35987
|
if (results.length > 0) {
|
|
35681
35988
|
const text2 = await manager.synthesizeRecalled(results);
|
|
35682
|
-
|
|
35683
|
-
|
|
35684
|
-
|
|
35685
|
-
|
|
35686
|
-
|
|
35687
|
-
|
|
35688
|
-
|
|
35689
|
-
|
|
35690
|
-
|
|
35691
|
-
|
|
35692
|
-
|
|
35693
|
-
await saveSessionSafe();
|
|
35989
|
+
if (injectRecalledMemoryOnce(messagesRef.current, text2)) {
|
|
35990
|
+
setEvents((e) => [
|
|
35991
|
+
...e,
|
|
35992
|
+
{
|
|
35993
|
+
kind: "memory",
|
|
35994
|
+
key: mkKey(),
|
|
35995
|
+
text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
|
|
35996
|
+
}
|
|
35997
|
+
]);
|
|
35998
|
+
await saveSessionSafe();
|
|
35999
|
+
}
|
|
35694
36000
|
}
|
|
35695
36001
|
} catch {
|
|
35696
36002
|
}
|
|
@@ -35703,6 +36009,10 @@ ${conflicts.join("\n")}` }
|
|
|
35703
36009
|
const plan = distillSessionPlan(messagesRef.current);
|
|
35704
36010
|
if (plan) {
|
|
35705
36011
|
sessionPlanRef.current = plan;
|
|
36012
|
+
if (cfg?.memoryEnabled && memoryManagerRef.current && sessionIdRef.current) {
|
|
36013
|
+
void memoryManagerRef.current.rememberPlan(plan, process.cwd(), sessionIdRef.current).catch(() => {
|
|
36014
|
+
});
|
|
36015
|
+
}
|
|
35706
36016
|
setShowPlanCompletePicker(true);
|
|
35707
36017
|
}
|
|
35708
36018
|
}
|
|
@@ -35872,7 +36182,7 @@ ${conflicts.join("\n")}` }
|
|
|
35872
36182
|
onCommandDelete: handleCommandDelete2,
|
|
35873
36183
|
lspServers: cfg?.lspServers ?? {},
|
|
35874
36184
|
lspScope,
|
|
35875
|
-
hasProjectDir: existsSync8(
|
|
36185
|
+
hasProjectDir: existsSync8(join38(process.cwd(), ".kimiflare")),
|
|
35876
36186
|
onLspSave: handleLspSave2,
|
|
35877
36187
|
themes: themeList(),
|
|
35878
36188
|
onPickTheme: handleThemePick,
|
|
@@ -36265,6 +36575,7 @@ var init_app = __esm({
|
|
|
36265
36575
|
init_sessions();
|
|
36266
36576
|
init_image();
|
|
36267
36577
|
init_usage_tracker();
|
|
36578
|
+
init_recall_inject();
|
|
36268
36579
|
init_loader2();
|
|
36269
36580
|
init_renderer2();
|
|
36270
36581
|
init_builtins();
|
|
@@ -36291,6 +36602,7 @@ var init_app = __esm({
|
|
|
36291
36602
|
init_manager_init();
|
|
36292
36603
|
init_run_compact();
|
|
36293
36604
|
init_distill();
|
|
36605
|
+
init_plan_resolver();
|
|
36294
36606
|
init_command_handlers();
|
|
36295
36607
|
init_app_helpers();
|
|
36296
36608
|
}
|