autopilot-ai 1.19.3 → 1.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1895 -416
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +279 -0
- package/dist/sdk/index.js +1204 -188
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -635,6 +635,15 @@ function readNumberEnv(name) {
|
|
|
635
635
|
const parsed = parseInt(raw, 10);
|
|
636
636
|
return Number.isNaN(parsed) ? void 0 : parsed;
|
|
637
637
|
}
|
|
638
|
+
function resolveTraceConfig(persisted) {
|
|
639
|
+
const envEnabled = readBooleanEnv("KIMIFLARE_TRACE");
|
|
640
|
+
const envRoot = process.env.KIMIFLARE_TRACE_DIR?.trim() || void 0;
|
|
641
|
+
if (envEnabled === void 0 && envRoot === void 0 && persisted === void 0) return void 0;
|
|
642
|
+
const trace = { enabled: envEnabled ?? persisted?.enabled ?? false };
|
|
643
|
+
const root = envRoot ?? persisted?.root;
|
|
644
|
+
if (root) trace.root = root;
|
|
645
|
+
return trace;
|
|
646
|
+
}
|
|
638
647
|
async function loadConfig() {
|
|
639
648
|
let persisted = {};
|
|
640
649
|
let hasFile = false;
|
|
@@ -726,7 +735,8 @@ async function loadConfig() {
|
|
|
726
735
|
workerPreReadMaxChars: readNumberEnv("KIMIFLARE_WORKER_PRE_READ_MAX_CHARS") ?? persisted.workerPreReadMaxChars,
|
|
727
736
|
permissions: persisted.permissions,
|
|
728
737
|
preferPullRequests: readBooleanEnv("KIMIFLARE_PREFER_PULL_REQUESTS") ?? persisted.preferPullRequests ?? true,
|
|
729
|
-
allowDirectPush: readBooleanEnv("KIMIFLARE_ALLOW_DIRECT_PUSH") ?? persisted.allowDirectPush ?? false
|
|
738
|
+
allowDirectPush: readBooleanEnv("KIMIFLARE_ALLOW_DIRECT_PUSH") ?? persisted.allowDirectPush ?? false,
|
|
739
|
+
trace: resolveTraceConfig(persisted.trace)
|
|
730
740
|
};
|
|
731
741
|
if (hasFile && hasLegacyFields(persisted)) {
|
|
732
742
|
await rewriteLegacyConfig(persisted, openrouterApiKey).catch(() => void 0);
|
|
@@ -1468,9 +1478,108 @@ function stripOldImages(messages, keepLastTurns) {
|
|
|
1468
1478
|
};
|
|
1469
1479
|
});
|
|
1470
1480
|
}
|
|
1481
|
+
function appendStoppedToolResults(messages, calls) {
|
|
1482
|
+
const answered = new Set(messages.filter((m) => m.role === "tool").map((m) => m.tool_call_id));
|
|
1483
|
+
let added = 0;
|
|
1484
|
+
for (const [id, name] of calls) {
|
|
1485
|
+
if (answered.has(id)) continue;
|
|
1486
|
+
messages.push({ role: "tool", tool_call_id: id, content: STOPPED_TOOL_RESULT, name });
|
|
1487
|
+
answered.add(id);
|
|
1488
|
+
added++;
|
|
1489
|
+
}
|
|
1490
|
+
return added;
|
|
1491
|
+
}
|
|
1492
|
+
function repairDanglingToolCalls(messages) {
|
|
1493
|
+
let inserted = 0;
|
|
1494
|
+
for (let i = 0; i < messages.length; i++) {
|
|
1495
|
+
const m = messages[i];
|
|
1496
|
+
if (m.role !== "assistant" || !m.tool_calls?.length) continue;
|
|
1497
|
+
let j = i + 1;
|
|
1498
|
+
const answered = /* @__PURE__ */ new Set();
|
|
1499
|
+
while (j < messages.length && messages[j].role === "tool") {
|
|
1500
|
+
const id = messages[j].tool_call_id;
|
|
1501
|
+
if (id) answered.add(id);
|
|
1502
|
+
j++;
|
|
1503
|
+
}
|
|
1504
|
+
const missing = m.tool_calls.filter((tc) => !answered.has(tc.id));
|
|
1505
|
+
if (missing.length === 0) continue;
|
|
1506
|
+
messages.splice(
|
|
1507
|
+
j,
|
|
1508
|
+
0,
|
|
1509
|
+
...missing.map((tc) => ({ role: "tool", tool_call_id: tc.id, content: STOPPED_TOOL_RESULT, name: tc.function.name }))
|
|
1510
|
+
);
|
|
1511
|
+
inserted += missing.length;
|
|
1512
|
+
i = j + missing.length - 1;
|
|
1513
|
+
}
|
|
1514
|
+
return inserted;
|
|
1515
|
+
}
|
|
1516
|
+
var STOPPED_TOOL_RESULT;
|
|
1471
1517
|
var init_messages = __esm({
|
|
1472
1518
|
"src/agent/messages.ts"() {
|
|
1473
1519
|
"use strict";
|
|
1520
|
+
STOPPED_TOOL_RESULT = "(stopped)";
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
// src/trace/blobs.ts
|
|
1525
|
+
import { createHash } from "crypto";
|
|
1526
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
1527
|
+
import { join as join8 } from "path";
|
|
1528
|
+
function sha256Hex(content) {
|
|
1529
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
1530
|
+
}
|
|
1531
|
+
function truncateUtf8(content, maxBytes) {
|
|
1532
|
+
const buf = Buffer.from(content, "utf8");
|
|
1533
|
+
if (buf.length <= maxBytes) return content;
|
|
1534
|
+
let end = maxBytes;
|
|
1535
|
+
while (end > 0 && (buf[end] & 192) === 128) end--;
|
|
1536
|
+
return buf.subarray(0, end).toString("utf8");
|
|
1537
|
+
}
|
|
1538
|
+
var DEFAULT_MAX_BLOB_BYTES, BlobStore;
|
|
1539
|
+
var init_blobs = __esm({
|
|
1540
|
+
"src/trace/blobs.ts"() {
|
|
1541
|
+
"use strict";
|
|
1542
|
+
DEFAULT_MAX_BLOB_BYTES = 2 * 1024 * 1024;
|
|
1543
|
+
BlobStore = class {
|
|
1544
|
+
constructor(dir, opts2 = {}) {
|
|
1545
|
+
this.dir = dir;
|
|
1546
|
+
this.maxBlobBytes = opts2.maxBlobBytes ?? DEFAULT_MAX_BLOB_BYTES;
|
|
1547
|
+
}
|
|
1548
|
+
dir;
|
|
1549
|
+
seen = /* @__PURE__ */ new Set();
|
|
1550
|
+
dirReady = false;
|
|
1551
|
+
maxBlobBytes;
|
|
1552
|
+
put(content) {
|
|
1553
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
1554
|
+
let stored = content;
|
|
1555
|
+
let truncated = false;
|
|
1556
|
+
if (bytes > this.maxBlobBytes) {
|
|
1557
|
+
stored = `${truncateUtf8(content, this.maxBlobBytes)}
|
|
1558
|
+
[truncated: ${bytes} bytes total]`;
|
|
1559
|
+
truncated = true;
|
|
1560
|
+
}
|
|
1561
|
+
const sha2563 = sha256Hex(stored);
|
|
1562
|
+
if (this.seen.has(sha2563)) return { sha256: sha2563, bytes, truncated, written: 0 };
|
|
1563
|
+
if (!this.dirReady) {
|
|
1564
|
+
mkdirSync2(this.dir, { recursive: true });
|
|
1565
|
+
this.dirReady = true;
|
|
1566
|
+
}
|
|
1567
|
+
const path = join8(this.dir, sha2563);
|
|
1568
|
+
let written = 0;
|
|
1569
|
+
if (!existsSync2(path)) {
|
|
1570
|
+
writeFileSync(path, stored, "utf8");
|
|
1571
|
+
written = Buffer.byteLength(stored, "utf8");
|
|
1572
|
+
}
|
|
1573
|
+
this.seen.add(sha2563);
|
|
1574
|
+
return { sha256: sha2563, bytes, truncated, written };
|
|
1575
|
+
}
|
|
1576
|
+
has(sha2563) {
|
|
1577
|
+
return this.seen.has(sha2563) || existsSync2(join8(this.dir, sha2563));
|
|
1578
|
+
}
|
|
1579
|
+
pathFor(sha2563) {
|
|
1580
|
+
return join8(this.dir, sha2563);
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1474
1583
|
}
|
|
1475
1584
|
});
|
|
1476
1585
|
|
|
@@ -1927,8 +2036,8 @@ var init_artifact_compaction = __esm({
|
|
|
1927
2036
|
|
|
1928
2037
|
// src/util/llm-dump.ts
|
|
1929
2038
|
import { homedir as homedir5 } from "os";
|
|
1930
|
-
import { join as
|
|
1931
|
-
import { mkdirSync as
|
|
2039
|
+
import { join as join9 } from "path";
|
|
2040
|
+
import { mkdirSync as mkdirSync3, appendFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1932
2041
|
function isLlmDumpEnabled() {
|
|
1933
2042
|
const raw = process.env.KIMIFLARE_DUMP_LLM;
|
|
1934
2043
|
if (raw === void 0) return false;
|
|
@@ -1938,11 +2047,11 @@ function isLlmDumpEnabled() {
|
|
|
1938
2047
|
function defaultDumpRoot() {
|
|
1939
2048
|
const override = process.env.KIMIFLARE_DUMP_LLM_DIR;
|
|
1940
2049
|
if (override && override.trim()) return override;
|
|
1941
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
1942
|
-
return
|
|
2050
|
+
const xdg = process.env.XDG_CONFIG_HOME || join9(homedir5(), ".config");
|
|
2051
|
+
return join9(xdg, "kimiflare", "llm-dumps");
|
|
1943
2052
|
}
|
|
1944
2053
|
function dumpDir(sessionId) {
|
|
1945
|
-
return
|
|
2054
|
+
return join9(defaultDumpRoot(), sessionId && sessionId.trim() ? sessionId : "nosession");
|
|
1946
2055
|
}
|
|
1947
2056
|
function messageChars(m) {
|
|
1948
2057
|
let chars = 0;
|
|
@@ -1999,12 +2108,12 @@ function writeLlmDump(record) {
|
|
|
1999
2108
|
if (!isLlmDumpEnabled()) return;
|
|
2000
2109
|
try {
|
|
2001
2110
|
const dir = dumpDir(record.meta.sessionId);
|
|
2002
|
-
|
|
2111
|
+
mkdirSync3(dir, { recursive: true });
|
|
2003
2112
|
const tsPart = safeSegment(record.meta.ts);
|
|
2004
2113
|
const turnPart = safeSegment(record.meta.turnId ?? "noturn");
|
|
2005
2114
|
const reqPart = safeSegment(record.meta.requestId);
|
|
2006
|
-
const file =
|
|
2007
|
-
|
|
2115
|
+
const file = join9(dir, `${tsPart}-${turnPart}-${reqPart}.json`);
|
|
2116
|
+
writeFileSync2(file, JSON.stringify(record, null, 2));
|
|
2008
2117
|
const summary = {
|
|
2009
2118
|
...record.meta,
|
|
2010
2119
|
...record.breakdown,
|
|
@@ -2014,7 +2123,7 @@ function writeLlmDump(record) {
|
|
|
2014
2123
|
usage: record.response.usage,
|
|
2015
2124
|
file
|
|
2016
2125
|
};
|
|
2017
|
-
appendFileSync(
|
|
2126
|
+
appendFileSync(join9(dir, "index.jsonl"), JSON.stringify(summary) + "\n");
|
|
2018
2127
|
} catch {
|
|
2019
2128
|
}
|
|
2020
2129
|
}
|
|
@@ -2257,41 +2366,89 @@ async function* runKimi(opts2) {
|
|
|
2257
2366
|
if (Object.keys(provider).length > 0) body.provider = provider;
|
|
2258
2367
|
if (vendorOf(opts2.model) === "anthropic") body.cache_control = { type: "ephemeral" };
|
|
2259
2368
|
}
|
|
2369
|
+
const dumpEnabled = isLlmDumpEnabled();
|
|
2370
|
+
const trace = opts2.trace?.enabled ? opts2.trace : null;
|
|
2371
|
+
const captured = dumpEnabled || trace ? captureRequest(body) : null;
|
|
2372
|
+
const response = {
|
|
2373
|
+
text: "",
|
|
2374
|
+
reasoning: "",
|
|
2375
|
+
reasoningDetails: [],
|
|
2376
|
+
toolCalls: [],
|
|
2377
|
+
finishReason: null,
|
|
2378
|
+
usage: null
|
|
2379
|
+
};
|
|
2260
2380
|
let dumpRecord = null;
|
|
2261
|
-
if (
|
|
2262
|
-
const dumpMessages = body.messages;
|
|
2263
|
-
const dumpTools = body.tools ?? [];
|
|
2264
|
-
const { messages: _m, tools: _t, ...params } = body;
|
|
2265
|
-
const dumpResponse = {
|
|
2266
|
-
text: "",
|
|
2267
|
-
reasoning: "",
|
|
2268
|
-
toolCalls: [],
|
|
2269
|
-
finishReason: null,
|
|
2270
|
-
usage: null
|
|
2271
|
-
};
|
|
2381
|
+
if (dumpEnabled && captured) {
|
|
2272
2382
|
dumpRecord = {
|
|
2273
2383
|
meta: {
|
|
2274
2384
|
requestId,
|
|
2275
2385
|
sessionId: opts2.sessionId ?? getLogSessionId(),
|
|
2276
|
-
turnId: getLogTurnId(),
|
|
2386
|
+
turnId: opts2.turnId ?? getLogTurnId(),
|
|
2277
2387
|
model: opts2.model,
|
|
2278
2388
|
url,
|
|
2279
2389
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
2280
2390
|
},
|
|
2281
2391
|
request: {
|
|
2282
|
-
system:
|
|
2283
|
-
messages:
|
|
2284
|
-
tools:
|
|
2285
|
-
params,
|
|
2286
|
-
rawSerialized:
|
|
2392
|
+
system: captured.messages.filter((m) => m.role === "system"),
|
|
2393
|
+
messages: captured.messages,
|
|
2394
|
+
tools: captured.tools,
|
|
2395
|
+
params: captured.params,
|
|
2396
|
+
rawSerialized: captured.rawSerialized
|
|
2287
2397
|
},
|
|
2288
|
-
breakdown:
|
|
2289
|
-
response
|
|
2398
|
+
breakdown: captured.breakdown,
|
|
2399
|
+
response
|
|
2290
2400
|
};
|
|
2291
2401
|
}
|
|
2402
|
+
const traceRequest = (attempt) => {
|
|
2403
|
+
if (!trace || !captured) return;
|
|
2404
|
+
trace.emit(
|
|
2405
|
+
"llm_request",
|
|
2406
|
+
{
|
|
2407
|
+
request_id: requestId,
|
|
2408
|
+
attempt,
|
|
2409
|
+
model: opts2.model,
|
|
2410
|
+
params: captured.params,
|
|
2411
|
+
request_blob: trace.blob(captured.rawSerialized) ?? "",
|
|
2412
|
+
messages_sha: captured.messagesSha,
|
|
2413
|
+
tools_sha: captured.toolsSha,
|
|
2414
|
+
estimated_tokens: captured.breakdown.estTokens
|
|
2415
|
+
},
|
|
2416
|
+
opts2.turnId ?? null
|
|
2417
|
+
);
|
|
2418
|
+
};
|
|
2419
|
+
const traceResponse = (startedAt2, error) => {
|
|
2420
|
+
if (!trace) return;
|
|
2421
|
+
const usage = response.usage;
|
|
2422
|
+
trace.emit(
|
|
2423
|
+
"llm_response",
|
|
2424
|
+
{
|
|
2425
|
+
request_id: requestId,
|
|
2426
|
+
text_blob: trace.blob(response.text) ?? "",
|
|
2427
|
+
...response.reasoning ? { reasoning_blob: trace.blob(response.reasoning) ?? "" } : {},
|
|
2428
|
+
...response.reasoningDetails.length ? { reasoning_details: response.reasoningDetails } : {},
|
|
2429
|
+
tool_calls: response.toolCalls.map((tc) => ({ id: tc.id, name: tc.name, arguments: tc.arguments })),
|
|
2430
|
+
finish_reason: response.finishReason,
|
|
2431
|
+
...usage ? {
|
|
2432
|
+
usage: {
|
|
2433
|
+
prompt_tokens: usage.prompt_tokens,
|
|
2434
|
+
completion_tokens: usage.completion_tokens,
|
|
2435
|
+
...usage.prompt_tokens_details?.cached_tokens !== void 0 ? { cached_tokens: usage.prompt_tokens_details.cached_tokens ?? void 0 } : {},
|
|
2436
|
+
...usage.cost !== void 0 ? { cost: usage.cost } : {}
|
|
2437
|
+
}
|
|
2438
|
+
} : {},
|
|
2439
|
+
...response.generationId ? { generation_id: response.generationId } : {},
|
|
2440
|
+
latency_ms: Math.round(performance.now() - startedAt2),
|
|
2441
|
+
aborted: opts2.signal?.aborted === true,
|
|
2442
|
+
...error !== void 0 ? { error } : {}
|
|
2443
|
+
},
|
|
2444
|
+
opts2.turnId ?? null
|
|
2445
|
+
);
|
|
2446
|
+
};
|
|
2292
2447
|
logger.debug("runKimi:request", { requestId, attempt: 0, model: opts2.model });
|
|
2293
2448
|
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
|
|
2294
2449
|
let res;
|
|
2450
|
+
const attemptStartedAt = performance.now();
|
|
2451
|
+
traceRequest(attempt);
|
|
2295
2452
|
try {
|
|
2296
2453
|
const headers = {
|
|
2297
2454
|
"Content-Type": "application/json",
|
|
@@ -2307,8 +2464,9 @@ async function* runKimi(opts2) {
|
|
|
2307
2464
|
signal: opts2.signal
|
|
2308
2465
|
});
|
|
2309
2466
|
} catch (fetchErr) {
|
|
2310
|
-
if (isAbortError(fetchErr)) throw fetchErr;
|
|
2311
2467
|
const msg = fetchErr instanceof Error ? fetchErr.message : String(fetchErr);
|
|
2468
|
+
traceResponse(attemptStartedAt, msg);
|
|
2469
|
+
if (isAbortError(fetchErr)) throw fetchErr;
|
|
2312
2470
|
logger.warn("runKimi:fetch_error", { requestId, attempt, error: msg });
|
|
2313
2471
|
if (attempt < MAX_ATTEMPTS - 1) {
|
|
2314
2472
|
const delay = Math.random() * (500 * 2 ** attempt);
|
|
@@ -2340,6 +2498,7 @@ async function* runKimi(opts2) {
|
|
|
2340
2498
|
err?.code,
|
|
2341
2499
|
status
|
|
2342
2500
|
);
|
|
2501
|
+
traceResponse(attemptStartedAt, apiErr.message);
|
|
2343
2502
|
if (isRetryable(apiErr, attempt)) {
|
|
2344
2503
|
const isRateLimit = apiErr.httpStatus === 429;
|
|
2345
2504
|
const baseDelay = isRateLimit ? 2e3 : 500;
|
|
@@ -2351,18 +2510,27 @@ async function* runKimi(opts2) {
|
|
|
2351
2510
|
}
|
|
2352
2511
|
throw apiErr;
|
|
2353
2512
|
}
|
|
2354
|
-
if (!res.body)
|
|
2513
|
+
if (!res.body) {
|
|
2514
|
+
const emptyErr = new KimiApiError("kimiflare: empty response body", void 0, res.status);
|
|
2515
|
+
traceResponse(attemptStartedAt, emptyErr.message);
|
|
2516
|
+
throw emptyErr;
|
|
2517
|
+
}
|
|
2355
2518
|
logger.debug("runKimi:stream_start", { requestId });
|
|
2519
|
+
let streamError;
|
|
2356
2520
|
try {
|
|
2357
2521
|
for await (const ev of parseStream(res.body, opts2.signal, opts2.idleTimeoutMs, opts2.postFirstByteIdleTimeoutMs)) {
|
|
2358
|
-
if (
|
|
2522
|
+
if (captured) accumulateDumpResponse(response, ev);
|
|
2359
2523
|
yield ev;
|
|
2360
2524
|
}
|
|
2525
|
+
} catch (streamErr) {
|
|
2526
|
+
streamError = streamErr instanceof Error ? streamErr.message : String(streamErr);
|
|
2527
|
+
throw streamErr;
|
|
2361
2528
|
} finally {
|
|
2362
2529
|
if (dumpRecord) {
|
|
2363
2530
|
dumpRecord.meta.attempt = attempt;
|
|
2364
2531
|
writeLlmDump(dumpRecord);
|
|
2365
2532
|
}
|
|
2533
|
+
traceResponse(attemptStartedAt, streamError);
|
|
2366
2534
|
}
|
|
2367
2535
|
logger.debug("runKimi:stream_end", { requestId });
|
|
2368
2536
|
return;
|
|
@@ -2439,16 +2607,36 @@ function describeRequestyHttpError(model, status, msg) {
|
|
|
2439
2607
|
}
|
|
2440
2608
|
return msg;
|
|
2441
2609
|
}
|
|
2610
|
+
function captureRequest(body) {
|
|
2611
|
+
const messages = body.messages;
|
|
2612
|
+
const tools = body.tools ?? [];
|
|
2613
|
+
const { messages: _m, tools: _t, ...params } = body;
|
|
2614
|
+
return {
|
|
2615
|
+
messages,
|
|
2616
|
+
tools,
|
|
2617
|
+
params,
|
|
2618
|
+
rawSerialized: stableStringify(body, jsonReplacer),
|
|
2619
|
+
messagesSha: sha256Hex(stableStringify(messages, jsonReplacer)),
|
|
2620
|
+
toolsSha: sha256Hex(stableStringify(tools, jsonReplacer)),
|
|
2621
|
+
breakdown: computeBreakdown(messages, tools)
|
|
2622
|
+
};
|
|
2623
|
+
}
|
|
2442
2624
|
function accumulateDumpResponse(resp, ev) {
|
|
2443
2625
|
switch (ev.type) {
|
|
2626
|
+
case "response_meta":
|
|
2627
|
+
if (ev.meta.generationId) resp.generationId = ev.meta.generationId;
|
|
2628
|
+
break;
|
|
2444
2629
|
case "text":
|
|
2445
2630
|
resp.text += ev.delta;
|
|
2446
2631
|
break;
|
|
2447
2632
|
case "reasoning":
|
|
2448
2633
|
resp.reasoning += ev.delta;
|
|
2449
2634
|
break;
|
|
2635
|
+
case "reasoning_details":
|
|
2636
|
+
resp.reasoningDetails = mergeReasoningDetails(resp.reasoningDetails, ev.details);
|
|
2637
|
+
break;
|
|
2450
2638
|
case "tool_call_complete":
|
|
2451
|
-
resp.toolCalls.push({ name: ev.name, arguments: ev.arguments });
|
|
2639
|
+
resp.toolCalls.push({ id: ev.id, name: ev.name, arguments: ev.arguments });
|
|
2452
2640
|
break;
|
|
2453
2641
|
case "usage":
|
|
2454
2642
|
resp.usage = ev.usage;
|
|
@@ -2674,6 +2862,7 @@ var init_client = __esm({
|
|
|
2674
2862
|
init_errors();
|
|
2675
2863
|
init_version();
|
|
2676
2864
|
init_messages();
|
|
2865
|
+
init_blobs();
|
|
2677
2866
|
init_logger();
|
|
2678
2867
|
init_log_sink();
|
|
2679
2868
|
init_llm_dump();
|
|
@@ -2746,7 +2935,7 @@ var init_recall_inject = __esm({
|
|
|
2746
2935
|
|
|
2747
2936
|
// src/storage-limits.ts
|
|
2748
2937
|
import { readdir as readdir2, stat as stat2, unlink } from "fs/promises";
|
|
2749
|
-
import { join as
|
|
2938
|
+
import { join as join10 } from "path";
|
|
2750
2939
|
async function listFilesByMtime(dir, pattern = /.*/) {
|
|
2751
2940
|
let entries;
|
|
2752
2941
|
try {
|
|
@@ -2757,7 +2946,7 @@ async function listFilesByMtime(dir, pattern = /.*/) {
|
|
|
2757
2946
|
const files = [];
|
|
2758
2947
|
for (const name of entries) {
|
|
2759
2948
|
if (!pattern.test(name)) continue;
|
|
2760
|
-
const p =
|
|
2949
|
+
const p = join10(dir, name);
|
|
2761
2950
|
try {
|
|
2762
2951
|
const s = await stat2(p);
|
|
2763
2952
|
if (s.isFile()) files.push({ path: p, mtime: s.mtime });
|
|
@@ -2834,7 +3023,13 @@ var init_storage_limits = __esm({
|
|
|
2834
3023
|
/** Memories older than this (days) are pruned. */
|
|
2835
3024
|
memoryMaxAgeDays: 90,
|
|
2836
3025
|
/** Max memories per repo. */
|
|
2837
|
-
memoryMaxEntries: 1e3
|
|
3026
|
+
memoryMaxEntries: 1e3,
|
|
3027
|
+
/** Session trace directories older than this (days) are pruned. */
|
|
3028
|
+
traceMaxAgeDays: 90,
|
|
3029
|
+
/** Max total size of all session traces (bytes). Oldest sessions go first. */
|
|
3030
|
+
traceMaxTotalBytes: 2 * 1024 * 1024 * 1024,
|
|
3031
|
+
/** Max size of a single session trace (bytes); recording stops at the cap. */
|
|
3032
|
+
traceMaxSessionBytes: 200 * 1024 * 1024
|
|
2838
3033
|
};
|
|
2839
3034
|
}
|
|
2840
3035
|
});
|
|
@@ -2842,13 +3037,13 @@ var init_storage_limits = __esm({
|
|
|
2842
3037
|
// src/cost-debug.ts
|
|
2843
3038
|
import { appendFile, mkdir as mkdir5 } from "fs/promises";
|
|
2844
3039
|
import { homedir as homedir6 } from "os";
|
|
2845
|
-
import { join as
|
|
3040
|
+
import { join as join11 } from "path";
|
|
2846
3041
|
function debugDir() {
|
|
2847
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
2848
|
-
return
|
|
3042
|
+
const xdg = process.env.XDG_DATA_HOME || join11(homedir6(), ".local", "share");
|
|
3043
|
+
return join11(xdg, "kimiflare");
|
|
2849
3044
|
}
|
|
2850
3045
|
function debugPath() {
|
|
2851
|
-
return
|
|
3046
|
+
return join11(debugDir(), "cost-debug.jsonl");
|
|
2852
3047
|
}
|
|
2853
3048
|
function now() {
|
|
2854
3049
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3562,7 +3757,7 @@ var require_isolated_vm = __commonJS({
|
|
|
3562
3757
|
});
|
|
3563
3758
|
|
|
3564
3759
|
// src/code-mode/sandbox.ts
|
|
3565
|
-
import { join as
|
|
3760
|
+
import { join as join12, dirname as dirname5 } from "path";
|
|
3566
3761
|
import { pathToFileURL } from "url";
|
|
3567
3762
|
function stripTypescript(code) {
|
|
3568
3763
|
let js = code;
|
|
@@ -3589,7 +3784,7 @@ async function loadTypescript(cwd) {
|
|
|
3589
3784
|
let dir = cwd;
|
|
3590
3785
|
while (dir !== dirname5(dir)) {
|
|
3591
3786
|
try {
|
|
3592
|
-
const tsPath =
|
|
3787
|
+
const tsPath = join12(dir, "node_modules", "typescript", "lib", "typescript.js");
|
|
3593
3788
|
return await import(pathToFileURL(tsPath).href);
|
|
3594
3789
|
} catch {
|
|
3595
3790
|
}
|
|
@@ -4433,11 +4628,11 @@ Prefer non-interactive flags when they exist (\`--yes\`, \`-m\`, \`--with-token\
|
|
|
4433
4628
|
|
|
4434
4629
|
// src/agent/system-prompt.ts
|
|
4435
4630
|
import { platform, release, homedir as homedir7 } from "os";
|
|
4436
|
-
import { basename, join as
|
|
4631
|
+
import { basename, join as join13 } from "path";
|
|
4437
4632
|
import { readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
4438
4633
|
function loadContextFile(cwd) {
|
|
4439
4634
|
for (const name of CONTEXT_FILENAMES) {
|
|
4440
|
-
const path =
|
|
4635
|
+
const path = join13(cwd, name);
|
|
4441
4636
|
try {
|
|
4442
4637
|
const s = statSync2(path);
|
|
4443
4638
|
if (!s.isFile() || s.size > MAX_CONTEXT_BYTES) continue;
|
|
@@ -4964,6 +5159,403 @@ var init_completion_check = __esm({
|
|
|
4964
5159
|
}
|
|
4965
5160
|
});
|
|
4966
5161
|
|
|
5162
|
+
// src/trace/paths.ts
|
|
5163
|
+
import { homedir as homedir8 } from "os";
|
|
5164
|
+
import { join as join14 } from "path";
|
|
5165
|
+
function defaultTraceRoot() {
|
|
5166
|
+
const xdg = process.env.XDG_DATA_HOME || join14(homedir8(), ".local", "share");
|
|
5167
|
+
return join14(xdg, "kimiflare", "traces");
|
|
5168
|
+
}
|
|
5169
|
+
function traceRoot(configRoot) {
|
|
5170
|
+
const env2 = process.env.KIMIFLARE_TRACE_DIR;
|
|
5171
|
+
if (env2 && env2.trim()) return env2.trim();
|
|
5172
|
+
if (configRoot && configRoot.trim()) return configRoot.trim();
|
|
5173
|
+
return defaultTraceRoot();
|
|
5174
|
+
}
|
|
5175
|
+
function safeSessionSegment(sessionId) {
|
|
5176
|
+
const cleaned = sessionId.replace(/[\\/\0]/g, "_").replace(/^\.+$/, "_");
|
|
5177
|
+
return cleaned || "session";
|
|
5178
|
+
}
|
|
5179
|
+
function sessionTraceDir(sessionId, root) {
|
|
5180
|
+
return join14(traceRoot(root), safeSessionSegment(sessionId));
|
|
5181
|
+
}
|
|
5182
|
+
function traceFilePath(sessionDir) {
|
|
5183
|
+
return join14(sessionDir, TRACE_FILE_NAME);
|
|
5184
|
+
}
|
|
5185
|
+
function blobsDir(sessionDir) {
|
|
5186
|
+
return join14(sessionDir, BLOBS_DIR_NAME);
|
|
5187
|
+
}
|
|
5188
|
+
var TRACE_FILE_NAME, BLOBS_DIR_NAME;
|
|
5189
|
+
var init_paths = __esm({
|
|
5190
|
+
"src/trace/paths.ts"() {
|
|
5191
|
+
"use strict";
|
|
5192
|
+
TRACE_FILE_NAME = "trace.jsonl";
|
|
5193
|
+
BLOBS_DIR_NAME = "blobs";
|
|
5194
|
+
}
|
|
5195
|
+
});
|
|
5196
|
+
|
|
5197
|
+
// src/trace/redact.ts
|
|
5198
|
+
function redactLight(text) {
|
|
5199
|
+
if (!text) return text;
|
|
5200
|
+
let out = text.replace(PEM_BLOCK, "<redacted-key>");
|
|
5201
|
+
for (const re of TOKEN_SHAPES) out = out.replace(re, "<redacted>");
|
|
5202
|
+
out = out.replace(KEY_VALUE, "$1$2<redacted>");
|
|
5203
|
+
return out;
|
|
5204
|
+
}
|
|
5205
|
+
function isSecretConfigKey(key) {
|
|
5206
|
+
const lower = key.toLowerCase();
|
|
5207
|
+
return SECRET_KEY_SUFFIXES.some((suffix) => lower.endsWith(suffix));
|
|
5208
|
+
}
|
|
5209
|
+
function redactConfig(value) {
|
|
5210
|
+
return redactValue(value, true);
|
|
5211
|
+
}
|
|
5212
|
+
function redactDeep(value) {
|
|
5213
|
+
return redactValue(value, false);
|
|
5214
|
+
}
|
|
5215
|
+
function redactValue(value, redactSecretKeys) {
|
|
5216
|
+
if (typeof value === "string") return redactLight(value);
|
|
5217
|
+
if (Array.isArray(value)) return value.map((v) => redactValue(v, redactSecretKeys));
|
|
5218
|
+
if (value && typeof value === "object") {
|
|
5219
|
+
const out = {};
|
|
5220
|
+
for (const [k, v] of Object.entries(value)) {
|
|
5221
|
+
if (v === void 0) continue;
|
|
5222
|
+
if (redactSecretKeys && isSecretConfigKey(k) && v !== null && v !== "") {
|
|
5223
|
+
out[k] = "<redacted>";
|
|
5224
|
+
} else {
|
|
5225
|
+
out[k] = redactValue(v, redactSecretKeys);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
return out;
|
|
5229
|
+
}
|
|
5230
|
+
return value;
|
|
5231
|
+
}
|
|
5232
|
+
var PEM_BLOCK, TOKEN_SHAPES, KEY_VALUE, SECRET_KEY_SUFFIXES;
|
|
5233
|
+
var init_redact = __esm({
|
|
5234
|
+
"src/trace/redact.ts"() {
|
|
5235
|
+
"use strict";
|
|
5236
|
+
PEM_BLOCK = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g;
|
|
5237
|
+
TOKEN_SHAPES = [
|
|
5238
|
+
/sk-or-v1-[A-Za-z0-9]+/g,
|
|
5239
|
+
/ghp_[A-Za-z0-9]+/g,
|
|
5240
|
+
/github_pat_[A-Za-z0-9_]+/g,
|
|
5241
|
+
/Bearer [A-Za-z0-9._-]+/g,
|
|
5242
|
+
/Basic [A-Za-z0-9+/=]+/g
|
|
5243
|
+
];
|
|
5244
|
+
KEY_VALUE = /(api[_-]?key|secret|token|password|authorization)(["']?\s*[:=]\s*["']?)[^\s"']+/gi;
|
|
5245
|
+
SECRET_KEY_SUFFIXES = ["apikey", "token", "secret", "password"];
|
|
5246
|
+
}
|
|
5247
|
+
});
|
|
5248
|
+
|
|
5249
|
+
// src/trace/types.ts
|
|
5250
|
+
var TRACE_SCHEMA_VERSION;
|
|
5251
|
+
var init_types = __esm({
|
|
5252
|
+
"src/trace/types.ts"() {
|
|
5253
|
+
"use strict";
|
|
5254
|
+
TRACE_SCHEMA_VERSION = 1;
|
|
5255
|
+
}
|
|
5256
|
+
});
|
|
5257
|
+
|
|
5258
|
+
// src/trace/recorder.ts
|
|
5259
|
+
import { randomUUID } from "crypto";
|
|
5260
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync3 } from "fs";
|
|
5261
|
+
function createNoopRecorder(sessionId = "") {
|
|
5262
|
+
return new NoopRecorder(sessionId);
|
|
5263
|
+
}
|
|
5264
|
+
function makeTurnId() {
|
|
5265
|
+
return randomUUID();
|
|
5266
|
+
}
|
|
5267
|
+
function createRecorder(opts2) {
|
|
5268
|
+
if (!opts2.enabled) return new NoopRecorder(opts2.sessionId);
|
|
5269
|
+
const dir = sessionTraceDir(opts2.sessionId, opts2.root);
|
|
5270
|
+
return new FileTraceRecorder(opts2.sessionId, dir, {
|
|
5271
|
+
maxBlobBytes: opts2.maxBlobBytes,
|
|
5272
|
+
maxSessionBytes: opts2.maxSessionBytes
|
|
5273
|
+
});
|
|
5274
|
+
}
|
|
5275
|
+
var NoopRecorder, FileTraceRecorder;
|
|
5276
|
+
var init_recorder = __esm({
|
|
5277
|
+
"src/trace/recorder.ts"() {
|
|
5278
|
+
"use strict";
|
|
5279
|
+
init_logger();
|
|
5280
|
+
init_log_sink();
|
|
5281
|
+
init_storage_limits();
|
|
5282
|
+
init_blobs();
|
|
5283
|
+
init_paths();
|
|
5284
|
+
init_redact();
|
|
5285
|
+
init_types();
|
|
5286
|
+
NoopRecorder = class {
|
|
5287
|
+
constructor(sessionId) {
|
|
5288
|
+
this.sessionId = sessionId;
|
|
5289
|
+
}
|
|
5290
|
+
sessionId;
|
|
5291
|
+
enabled = false;
|
|
5292
|
+
dir = null;
|
|
5293
|
+
emit() {
|
|
5294
|
+
}
|
|
5295
|
+
blob() {
|
|
5296
|
+
return null;
|
|
5297
|
+
}
|
|
5298
|
+
flush() {
|
|
5299
|
+
return Promise.resolve();
|
|
5300
|
+
}
|
|
5301
|
+
};
|
|
5302
|
+
FileTraceRecorder = class {
|
|
5303
|
+
constructor(sessionId, dir, opts2) {
|
|
5304
|
+
this.sessionId = sessionId;
|
|
5305
|
+
this.dir = dir;
|
|
5306
|
+
this.file = traceFilePath(dir);
|
|
5307
|
+
this.blobs = new BlobStore(blobsDir(dir), { maxBlobBytes: opts2.maxBlobBytes });
|
|
5308
|
+
this.maxSessionBytes = opts2.maxSessionBytes ?? RETENTION.traceMaxSessionBytes;
|
|
5309
|
+
}
|
|
5310
|
+
sessionId;
|
|
5311
|
+
enabled = true;
|
|
5312
|
+
dir;
|
|
5313
|
+
file;
|
|
5314
|
+
blobs;
|
|
5315
|
+
maxSessionBytes;
|
|
5316
|
+
seq = 0;
|
|
5317
|
+
bytesWritten = 0;
|
|
5318
|
+
dirReady = false;
|
|
5319
|
+
emit(type, payload, turnId) {
|
|
5320
|
+
if (!this.enabled) return;
|
|
5321
|
+
try {
|
|
5322
|
+
const event = {
|
|
5323
|
+
v: TRACE_SCHEMA_VERSION,
|
|
5324
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5325
|
+
seq: this.seq,
|
|
5326
|
+
session_id: this.sessionId,
|
|
5327
|
+
turn_id: turnId === void 0 ? getLogTurnId() : turnId,
|
|
5328
|
+
type,
|
|
5329
|
+
payload: redactDeep(payload)
|
|
5330
|
+
};
|
|
5331
|
+
if (!this.dirReady) {
|
|
5332
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
5333
|
+
this.dirReady = true;
|
|
5334
|
+
this.resumeSeq();
|
|
5335
|
+
event.seq = this.seq;
|
|
5336
|
+
}
|
|
5337
|
+
const line = JSON.stringify(event) + "\n";
|
|
5338
|
+
if (!this.ensureBudget(Buffer.byteLength(line, "utf8"))) return;
|
|
5339
|
+
appendFileSync2(this.file, line, "utf8");
|
|
5340
|
+
this.seq++;
|
|
5341
|
+
} catch (err) {
|
|
5342
|
+
this.fail(err);
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
blob(content) {
|
|
5346
|
+
if (!this.enabled) return null;
|
|
5347
|
+
try {
|
|
5348
|
+
const result2 = this.blobs.put(redactLight(content));
|
|
5349
|
+
if (result2.written > 0) this.ensureBudget(result2.written);
|
|
5350
|
+
return result2.sha256;
|
|
5351
|
+
} catch (err) {
|
|
5352
|
+
this.fail(err);
|
|
5353
|
+
return null;
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
flush() {
|
|
5357
|
+
return Promise.resolve();
|
|
5358
|
+
}
|
|
5359
|
+
/** Continue `seq` after the lines already in an existing trace file. */
|
|
5360
|
+
resumeSeq() {
|
|
5361
|
+
if (!existsSync3(this.file)) return;
|
|
5362
|
+
const existing = readFileSync3(this.file, "utf8");
|
|
5363
|
+
let lines = 0;
|
|
5364
|
+
for (let i = 0; i < existing.length; i++) if (existing.charCodeAt(i) === 10) lines++;
|
|
5365
|
+
this.seq = lines;
|
|
5366
|
+
this.bytesWritten += Buffer.byteLength(existing, "utf8");
|
|
5367
|
+
}
|
|
5368
|
+
/** Account for `bytes`; returns false (and disables) once the session cap is exceeded. */
|
|
5369
|
+
ensureBudget(bytes) {
|
|
5370
|
+
this.bytesWritten += bytes;
|
|
5371
|
+
if (this.bytesWritten > this.maxSessionBytes) {
|
|
5372
|
+
this.enabled = false;
|
|
5373
|
+
logger.warn("trace:session_cap", {
|
|
5374
|
+
session_id: this.sessionId,
|
|
5375
|
+
dir: this.dir,
|
|
5376
|
+
max_bytes: this.maxSessionBytes
|
|
5377
|
+
});
|
|
5378
|
+
return false;
|
|
5379
|
+
}
|
|
5380
|
+
return true;
|
|
5381
|
+
}
|
|
5382
|
+
fail(err) {
|
|
5383
|
+
this.enabled = false;
|
|
5384
|
+
logger.warn("trace:write_failed", {
|
|
5385
|
+
session_id: this.sessionId,
|
|
5386
|
+
dir: this.dir,
|
|
5387
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5388
|
+
});
|
|
5389
|
+
}
|
|
5390
|
+
};
|
|
5391
|
+
}
|
|
5392
|
+
});
|
|
5393
|
+
|
|
5394
|
+
// src/cost-attribution/git-diff.ts
|
|
5395
|
+
import { execFile } from "child_process";
|
|
5396
|
+
import { promisify } from "util";
|
|
5397
|
+
function parseNumstat(raw) {
|
|
5398
|
+
const entries = [];
|
|
5399
|
+
for (const line of raw.split("\n")) {
|
|
5400
|
+
if (!line.trim()) continue;
|
|
5401
|
+
const parts = line.split(" ");
|
|
5402
|
+
if (parts.length < 3) continue;
|
|
5403
|
+
const ins = parseInt(parts[0], 10);
|
|
5404
|
+
const del = parseInt(parts[1], 10);
|
|
5405
|
+
entries.push({
|
|
5406
|
+
file: parts.slice(2).join(" "),
|
|
5407
|
+
insertions: Number.isNaN(ins) ? 0 : ins,
|
|
5408
|
+
deletions: Number.isNaN(del) ? 0 : del
|
|
5409
|
+
});
|
|
5410
|
+
}
|
|
5411
|
+
return entries;
|
|
5412
|
+
}
|
|
5413
|
+
async function gitNumstat(cwd, opts2 = {}) {
|
|
5414
|
+
let raw;
|
|
5415
|
+
try {
|
|
5416
|
+
const args = ["diff", "--numstat"];
|
|
5417
|
+
if (opts2.againstHead) args.push("HEAD");
|
|
5418
|
+
args.push("--", ".");
|
|
5419
|
+
try {
|
|
5420
|
+
raw = (await execFileAsync("git", args, { cwd, timeout: 5e3 })).stdout;
|
|
5421
|
+
} catch (err) {
|
|
5422
|
+
if (!opts2.againstHead) throw err;
|
|
5423
|
+
raw = (await execFileAsync("git", ["diff", "--numstat", "--", "."], { cwd, timeout: 5e3 })).stdout;
|
|
5424
|
+
}
|
|
5425
|
+
} catch {
|
|
5426
|
+
return null;
|
|
5427
|
+
}
|
|
5428
|
+
const entries = parseNumstat(raw);
|
|
5429
|
+
if (opts2.includeUntracked) {
|
|
5430
|
+
try {
|
|
5431
|
+
const { stdout } = await execFileAsync("git", ["ls-files", "--others", "--exclude-standard"], { cwd, timeout: 5e3 });
|
|
5432
|
+
const { readFile: readFile32, stat: stat11 } = await import("fs/promises");
|
|
5433
|
+
const { join: join54 } = await import("path");
|
|
5434
|
+
for (const file of stdout.split("\n").filter(Boolean)) {
|
|
5435
|
+
let lines = 0;
|
|
5436
|
+
try {
|
|
5437
|
+
const path = join54(cwd, file);
|
|
5438
|
+
const size = (await stat11(path)).size;
|
|
5439
|
+
if (size > 0 && size <= 1024 * 1024) {
|
|
5440
|
+
const text = await readFile32(path, "utf8");
|
|
5441
|
+
lines = text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
|
|
5442
|
+
}
|
|
5443
|
+
} catch {
|
|
5444
|
+
}
|
|
5445
|
+
entries.push({ file, insertions: lines, deletions: 0 });
|
|
5446
|
+
raw += `${lines} 0 ${file}
|
|
5447
|
+
`;
|
|
5448
|
+
}
|
|
5449
|
+
} catch {
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
return { raw, entries };
|
|
5453
|
+
}
|
|
5454
|
+
async function gitPatch(cwd, maxBytes) {
|
|
5455
|
+
try {
|
|
5456
|
+
let stdout;
|
|
5457
|
+
try {
|
|
5458
|
+
stdout = (await execFileAsync("git", ["diff", "HEAD", "--", "."], { cwd, timeout: 1e4, maxBuffer: maxBytes * 4 })).stdout;
|
|
5459
|
+
} catch {
|
|
5460
|
+
stdout = (await execFileAsync("git", ["diff", "--", "."], { cwd, timeout: 1e4, maxBuffer: maxBytes * 4 })).stdout;
|
|
5461
|
+
}
|
|
5462
|
+
return Buffer.byteLength(stdout, "utf8") <= maxBytes ? stdout : null;
|
|
5463
|
+
} catch {
|
|
5464
|
+
return null;
|
|
5465
|
+
}
|
|
5466
|
+
}
|
|
5467
|
+
var execFileAsync;
|
|
5468
|
+
var init_git_diff = __esm({
|
|
5469
|
+
"src/cost-attribution/git-diff.ts"() {
|
|
5470
|
+
"use strict";
|
|
5471
|
+
execFileAsync = promisify(execFile);
|
|
5472
|
+
}
|
|
5473
|
+
});
|
|
5474
|
+
|
|
5475
|
+
// src/trace/git-delta.ts
|
|
5476
|
+
function toMap(entries) {
|
|
5477
|
+
return new Map(entries.map((e) => [e.file, e]));
|
|
5478
|
+
}
|
|
5479
|
+
function diffNumstat(before, after) {
|
|
5480
|
+
const b = toMap(before);
|
|
5481
|
+
const a = toMap(after);
|
|
5482
|
+
const files = /* @__PURE__ */ new Set([...b.keys(), ...a.keys()]);
|
|
5483
|
+
let insertions = 0;
|
|
5484
|
+
let deletions = 0;
|
|
5485
|
+
const changed = [];
|
|
5486
|
+
for (const file of files) {
|
|
5487
|
+
const x = b.get(file) ?? { file, insertions: 0, deletions: 0 };
|
|
5488
|
+
const y = a.get(file) ?? { file, insertions: 0, deletions: 0 };
|
|
5489
|
+
const di = y.insertions - x.insertions;
|
|
5490
|
+
const dd = y.deletions - x.deletions;
|
|
5491
|
+
if (di === 0 && dd === 0) continue;
|
|
5492
|
+
changed.push(file);
|
|
5493
|
+
insertions += Math.max(0, di);
|
|
5494
|
+
deletions += Math.max(0, dd);
|
|
5495
|
+
}
|
|
5496
|
+
changed.sort();
|
|
5497
|
+
return { files_changed: changed.length, insertions, deletions, files: changed };
|
|
5498
|
+
}
|
|
5499
|
+
function rememberGitDelta(sessionId, turnId, files) {
|
|
5500
|
+
if (files.length === 0) return;
|
|
5501
|
+
lastDeltaBySession.set(sessionId, { turnId, files });
|
|
5502
|
+
}
|
|
5503
|
+
function detectGitRevert(sessionId, command) {
|
|
5504
|
+
const last = lastDeltaBySession.get(sessionId);
|
|
5505
|
+
if (!last) return null;
|
|
5506
|
+
if (!REVERT_COMMAND.test(command)) return null;
|
|
5507
|
+
const isStash = /git\s+stash\b/.test(command) && !/git\s+stash\s+(pop|apply|list|show|drop)\b/.test(command);
|
|
5508
|
+
if (isStash) return { turnId: last.turnId };
|
|
5509
|
+
if (/git\s+(checkout\s+--|restore)\s*$/.test(command.trim())) return null;
|
|
5510
|
+
const hit = last.files.some((file) => {
|
|
5511
|
+
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
5512
|
+
return command.includes(file) || base && new RegExp(`(^|[\\s/'"])${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(['"\\s]|$)`).test(command);
|
|
5513
|
+
});
|
|
5514
|
+
if (hit) return { turnId: last.turnId };
|
|
5515
|
+
if (/git\s+restore\s+(\.|--staged\s+\.)(\s|$)/.test(command) || /git\s+checkout\s+--\s+\.(\s|$)/.test(command)) return { turnId: last.turnId };
|
|
5516
|
+
return null;
|
|
5517
|
+
}
|
|
5518
|
+
async function beginGitDelta(opts2) {
|
|
5519
|
+
if (!opts2.trace.enabled) return null;
|
|
5520
|
+
const before = await gitNumstat(opts2.cwd, { againstHead: true, includeUntracked: true });
|
|
5521
|
+
if (!before) return null;
|
|
5522
|
+
let done = false;
|
|
5523
|
+
return {
|
|
5524
|
+
async finish() {
|
|
5525
|
+
if (done) return;
|
|
5526
|
+
done = true;
|
|
5527
|
+
const after = await gitNumstat(opts2.cwd, { againstHead: true, includeUntracked: true });
|
|
5528
|
+
if (!after || !opts2.trace.enabled) return;
|
|
5529
|
+
const delta = diffNumstat(before.entries, after.entries);
|
|
5530
|
+
const patch = delta.files_changed > 0 ? await gitPatch(opts2.cwd, MAX_PATCH_BYTES) : null;
|
|
5531
|
+
opts2.trace.emit(
|
|
5532
|
+
"outcome",
|
|
5533
|
+
{
|
|
5534
|
+
kind: "git_delta",
|
|
5535
|
+
turn_id: opts2.turnId,
|
|
5536
|
+
files_changed: delta.files_changed,
|
|
5537
|
+
insertions: delta.insertions,
|
|
5538
|
+
deletions: delta.deletions,
|
|
5539
|
+
numstat_blob: opts2.trace.blob(after.raw) ?? "",
|
|
5540
|
+
...patch ? { patch_blob: opts2.trace.blob(patch) ?? "" } : {}
|
|
5541
|
+
},
|
|
5542
|
+
opts2.turnId
|
|
5543
|
+
);
|
|
5544
|
+
if (opts2.sessionId) rememberGitDelta(opts2.sessionId, opts2.turnId, delta.files);
|
|
5545
|
+
}
|
|
5546
|
+
};
|
|
5547
|
+
}
|
|
5548
|
+
var MAX_PATCH_BYTES, lastDeltaBySession, REVERT_COMMAND;
|
|
5549
|
+
var init_git_delta = __esm({
|
|
5550
|
+
"src/trace/git-delta.ts"() {
|
|
5551
|
+
"use strict";
|
|
5552
|
+
init_git_diff();
|
|
5553
|
+
MAX_PATCH_BYTES = 512 * 1024;
|
|
5554
|
+
lastDeltaBySession = /* @__PURE__ */ new Map();
|
|
5555
|
+
REVERT_COMMAND = /(^|[\s;&|(])git\s+(checkout\s+--|restore\b|stash\b)/;
|
|
5556
|
+
}
|
|
5557
|
+
});
|
|
5558
|
+
|
|
4967
5559
|
// src/agent/loop.ts
|
|
4968
5560
|
function getSessionWebFetchHistory(sessionId) {
|
|
4969
5561
|
const key = sessionId ?? "default";
|
|
@@ -5002,7 +5594,90 @@ function raceWithSignal(promise, signal) {
|
|
|
5002
5594
|
]);
|
|
5003
5595
|
}
|
|
5004
5596
|
async function runAgentTurn(opts2) {
|
|
5005
|
-
const
|
|
5597
|
+
const tr = {
|
|
5598
|
+
trace: opts2.trace ?? createNoopRecorder(opts2.sessionId ?? ""),
|
|
5599
|
+
turnId: opts2.turnId ?? makeTurnId(),
|
|
5600
|
+
startedAt: performance.now(),
|
|
5601
|
+
toolsUsed: [],
|
|
5602
|
+
partialText: "",
|
|
5603
|
+
finalText: null,
|
|
5604
|
+
costUsd: 0,
|
|
5605
|
+
endReason: null
|
|
5606
|
+
};
|
|
5607
|
+
const endTurn = (reason, finalText) => {
|
|
5608
|
+
if (!tr.trace.enabled) return;
|
|
5609
|
+
const finalBlob = finalText ? tr.trace.blob(finalText) : null;
|
|
5610
|
+
tr.trace.emit(
|
|
5611
|
+
"turn_end",
|
|
5612
|
+
{
|
|
5613
|
+
reason,
|
|
5614
|
+
tools_used: tr.toolsUsed,
|
|
5615
|
+
...tr.costUsd > 0 ? { cost_usd: tr.costUsd } : {},
|
|
5616
|
+
duration_ms: Math.round(performance.now() - tr.startedAt),
|
|
5617
|
+
...finalBlob ? { final_text_blob: finalBlob } : {}
|
|
5618
|
+
},
|
|
5619
|
+
tr.turnId
|
|
5620
|
+
);
|
|
5621
|
+
};
|
|
5622
|
+
const gitDelta = await beginGitDelta({ trace: tr.trace, turnId: tr.turnId, sessionId: opts2.sessionId, cwd: opts2.cwd }).catch(
|
|
5623
|
+
() => null
|
|
5624
|
+
);
|
|
5625
|
+
try {
|
|
5626
|
+
await runAgentTurnInner(opts2, tr);
|
|
5627
|
+
endTurn(tr.endReason ?? "complete", tr.finalText);
|
|
5628
|
+
} catch (err) {
|
|
5629
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
5630
|
+
endTurn("aborted", tr.partialText || tr.finalText);
|
|
5631
|
+
} else if (err instanceof AgentLoopError || err instanceof BudgetExhaustedError) {
|
|
5632
|
+
endTurn("guardrail", tr.finalText);
|
|
5633
|
+
} else {
|
|
5634
|
+
endTurn("error", tr.partialText || tr.finalText);
|
|
5635
|
+
}
|
|
5636
|
+
throw err;
|
|
5637
|
+
} finally {
|
|
5638
|
+
await gitDelta?.finish().catch(() => void 0);
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
async function runAgentTurnInner(opts2, tr) {
|
|
5642
|
+
const turnStart = tr.startedAt;
|
|
5643
|
+
const { trace, turnId } = tr;
|
|
5644
|
+
const notifyGuardrail = (ev) => {
|
|
5645
|
+
if (ev.kind !== "completion_nudge") trace.emit("guardrail", { kind: ev.kind, message: ev.message }, turnId);
|
|
5646
|
+
opts2.callbacks.onGuardrail?.(ev);
|
|
5647
|
+
};
|
|
5648
|
+
const traceBlocked = (tc, result2, errorCode, redirected = false) => {
|
|
5649
|
+
if (!trace.enabled) return;
|
|
5650
|
+
const argsBlob = trace.blob(tc.function.arguments) ?? "";
|
|
5651
|
+
trace.emit(
|
|
5652
|
+
"tool_call",
|
|
5653
|
+
{
|
|
5654
|
+
tool_call_id: tc.id,
|
|
5655
|
+
name: tc.function.name,
|
|
5656
|
+
args_blob: argsBlob,
|
|
5657
|
+
...tc.function.arguments.length <= 2048 ? { args_inline: parseArgsObject(tc.function.arguments) } : {},
|
|
5658
|
+
needs_permission: false,
|
|
5659
|
+
code_mode_redirected: redirected
|
|
5660
|
+
},
|
|
5661
|
+
turnId
|
|
5662
|
+
);
|
|
5663
|
+
const blob = trace.blob(result2.content) ?? "";
|
|
5664
|
+
const bytes = Buffer.byteLength(result2.content, "utf8");
|
|
5665
|
+
trace.emit(
|
|
5666
|
+
"tool_result",
|
|
5667
|
+
{
|
|
5668
|
+
tool_call_id: tc.id,
|
|
5669
|
+
name: tc.function.name,
|
|
5670
|
+
ok: false,
|
|
5671
|
+
error_code: errorCode,
|
|
5672
|
+
raw_blob: blob,
|
|
5673
|
+
raw_bytes: bytes,
|
|
5674
|
+
reduced_blob: blob,
|
|
5675
|
+
reduced_bytes: bytes,
|
|
5676
|
+
duration_ms: 0
|
|
5677
|
+
},
|
|
5678
|
+
turnId
|
|
5679
|
+
);
|
|
5680
|
+
};
|
|
5006
5681
|
logger.info("turn:start", { sessionId: opts2.sessionId, codeMode: opts2.codeMode ?? false });
|
|
5007
5682
|
const max = opts2.maxToolIterations ?? 200;
|
|
5008
5683
|
const limitBehavior = opts2.toolLimitBehavior ?? (opts2.continueOnLimit ? "continue" : "throw");
|
|
@@ -5164,6 +5839,18 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5164
5839
|
const webFetchHistory = getSessionWebFetchHistory(opts2.sessionId);
|
|
5165
5840
|
let webFetchesThisTurn = 0;
|
|
5166
5841
|
let codeModeRedirects = 0;
|
|
5842
|
+
const noteCodeModeRedirect = () => {
|
|
5843
|
+
if (codeModeRedirects === MAX_CODE_MODE_REDIRECTS) {
|
|
5844
|
+
trace.emit(
|
|
5845
|
+
"guardrail",
|
|
5846
|
+
{
|
|
5847
|
+
kind: "code_mode_redirect_cap",
|
|
5848
|
+
message: `Code Mode redirect cap (${MAX_CODE_MODE_REDIRECTS}) reached \u2014 direct tool calls now execute normally.`
|
|
5849
|
+
},
|
|
5850
|
+
turnId
|
|
5851
|
+
);
|
|
5852
|
+
}
|
|
5853
|
+
};
|
|
5167
5854
|
const MAX_WEB_FETCH_PER_TURN = 5;
|
|
5168
5855
|
let cumulativePromptTokens = 0;
|
|
5169
5856
|
let iter = 0;
|
|
@@ -5201,7 +5888,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5201
5888
|
role: "system",
|
|
5202
5889
|
content: `You have reached the hard safety ceiling of ${hardCeiling} tool iterations for this turn. Do not call any more tools. Summarize what you accomplished, what remains unfinished, and the concrete next steps needed to complete the task.`
|
|
5203
5890
|
});
|
|
5204
|
-
|
|
5891
|
+
notifyGuardrail({
|
|
5205
5892
|
kind: "limit_ceiling",
|
|
5206
5893
|
message: `Tool-iteration ceiling (${hardCeiling}) reached \u2014 wrapping up the turn with a summary.`,
|
|
5207
5894
|
totalIterations: totalIter
|
|
@@ -5213,17 +5900,18 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5213
5900
|
content: "You have reached the tool-call limit for this session. The counter has been reset so you can continue working. Please proceed with your task."
|
|
5214
5901
|
});
|
|
5215
5902
|
iter = 0;
|
|
5216
|
-
|
|
5903
|
+
notifyGuardrail({
|
|
5217
5904
|
kind: "limit_reset",
|
|
5218
5905
|
message: `Tool-call limit (${max}) reached \u2014 counter reset automatically (${totalIter}/${hardCeiling} total).`,
|
|
5219
5906
|
totalIterations: totalIter
|
|
5220
5907
|
});
|
|
5221
5908
|
} else if (limitBehavior === "stop") {
|
|
5222
|
-
|
|
5909
|
+
notifyGuardrail({
|
|
5223
5910
|
kind: "limit_stopped",
|
|
5224
5911
|
message: `Tool-call limit (${max}) reached \u2014 turn stopped.`,
|
|
5225
5912
|
totalIterations: totalIter
|
|
5226
5913
|
});
|
|
5914
|
+
tr.endReason = "guardrail";
|
|
5227
5915
|
await fireStopHook();
|
|
5228
5916
|
return;
|
|
5229
5917
|
} else {
|
|
@@ -5240,6 +5928,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5240
5928
|
let reasoning = "";
|
|
5241
5929
|
let responseMeta;
|
|
5242
5930
|
let reasoningDetails = [];
|
|
5931
|
+
tr.partialText = "";
|
|
5243
5932
|
opts2.callbacks.onAssistantStart?.();
|
|
5244
5933
|
const stripReasoning = process.env.KIMIFLARE_STRIP_REASONING === "1";
|
|
5245
5934
|
const shadowStrip = process.env.KIMIFLARE_SHADOW_STRIP === "1";
|
|
@@ -5286,6 +5975,17 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5286
5975
|
budgetTokens: maxPromptTokens
|
|
5287
5976
|
};
|
|
5288
5977
|
logger.info("context:compacted", { sessionId: opts2.sessionId, ...info });
|
|
5978
|
+
trace.emit(
|
|
5979
|
+
"compaction",
|
|
5980
|
+
{
|
|
5981
|
+
method: "preflight",
|
|
5982
|
+
tokens_before: info.tokensBefore,
|
|
5983
|
+
tokens_after: info.tokensAfter,
|
|
5984
|
+
turns_removed: info.turnsRemoved,
|
|
5985
|
+
artifacts_archived: info.artifactsArchived
|
|
5986
|
+
},
|
|
5987
|
+
turnId
|
|
5988
|
+
);
|
|
5289
5989
|
opts2.callbacks.onCompacted?.(info);
|
|
5290
5990
|
}
|
|
5291
5991
|
}
|
|
@@ -5305,7 +6005,9 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5305
6005
|
reasoningEffort: opts2.reasoningEffort,
|
|
5306
6006
|
sessionId: opts2.sessionId,
|
|
5307
6007
|
idleTimeoutMs: opts2.idleTimeoutMs ?? 6e4,
|
|
5308
|
-
postFirstByteIdleTimeoutMs: opts2.postFirstByteIdleTimeoutMs
|
|
6008
|
+
postFirstByteIdleTimeoutMs: opts2.postFirstByteIdleTimeoutMs,
|
|
6009
|
+
trace,
|
|
6010
|
+
turnId
|
|
5309
6011
|
});
|
|
5310
6012
|
let gotFirstChunk = false;
|
|
5311
6013
|
for await (const ev of events) {
|
|
@@ -5327,6 +6029,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5327
6029
|
break;
|
|
5328
6030
|
case "text":
|
|
5329
6031
|
content += ev.delta;
|
|
6032
|
+
tr.partialText = content;
|
|
5330
6033
|
opts2.callbacks.onTextDelta?.(ev.delta);
|
|
5331
6034
|
break;
|
|
5332
6035
|
case "tool_call_start":
|
|
@@ -5343,6 +6046,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5343
6046
|
function: { name: normalizeToolName(ev.name, opts2.tools), arguments: safeArgs }
|
|
5344
6047
|
};
|
|
5345
6048
|
toolCalls.push(call);
|
|
6049
|
+
tr.toolsUsed.push(call.function.name);
|
|
5346
6050
|
opts2.callbacks.onToolCallFinalized?.(call);
|
|
5347
6051
|
break;
|
|
5348
6052
|
}
|
|
@@ -5356,6 +6060,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5356
6060
|
}
|
|
5357
6061
|
if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
5358
6062
|
if (lastUsage) {
|
|
6063
|
+
if (typeof lastUsage.cost === "number") tr.costUsd += lastUsage.cost;
|
|
5359
6064
|
opts2.callbacks.onUsageFinal?.(lastUsage, responseMeta);
|
|
5360
6065
|
cumulativePromptTokens += lastUsage.prompt_tokens;
|
|
5361
6066
|
if (!budgetExhausted && opts2.maxInputTokens !== void 0 && opts2.maxInputTokens > 0 && cumulativePromptTokens >= opts2.maxInputTokens) {
|
|
@@ -5384,8 +6089,10 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5384
6089
|
}
|
|
5385
6090
|
}
|
|
5386
6091
|
opts2.messages.push(assistantMsg);
|
|
6092
|
+
tr.finalText = typeof assistantMsg.content === "string" ? assistantMsg.content : null;
|
|
5387
6093
|
opts2.callbacks.onAssistantFinal?.(assistantMsg);
|
|
5388
6094
|
if (finalizeReason !== null) {
|
|
6095
|
+
tr.endReason = "guardrail";
|
|
5389
6096
|
logger.info("turn:finalized", { sessionId: opts2.sessionId, reason: finalizeReason, totalIter });
|
|
5390
6097
|
if (budgetExhausted) throw new BudgetExhaustedError();
|
|
5391
6098
|
await fireStopHook();
|
|
@@ -5424,11 +6131,12 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5424
6131
|
if (shouldCheckCompletion(input, opts2.intentClassification?.tier)) {
|
|
5425
6132
|
const p = await opts2.completionCheck(input, opts2.signal).catch(() => null);
|
|
5426
6133
|
if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
6134
|
+
if (p !== null) trace.emit("completion_check", { probability: p, nudged: p < INCOMPLETE_THRESHOLD }, turnId);
|
|
5427
6135
|
if (p !== null && p < INCOMPLETE_THRESHOLD) {
|
|
5428
6136
|
completionNudges++;
|
|
5429
6137
|
logger.info("turn:completion_nudge", { sessionId: opts2.sessionId, probability: p });
|
|
5430
6138
|
opts2.messages.push({ role: "system", content: CONTINUE_NUDGE });
|
|
5431
|
-
|
|
6139
|
+
notifyGuardrail({
|
|
5432
6140
|
kind: "completion_nudge",
|
|
5433
6141
|
message: "The agent stopped before finishing \u2014 asked it to continue.",
|
|
5434
6142
|
probability: p
|
|
@@ -5468,6 +6176,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5468
6176
|
kind: "blocked",
|
|
5469
6177
|
tc,
|
|
5470
6178
|
loopSignature,
|
|
6179
|
+
errorCode: "loop_guardrail",
|
|
5471
6180
|
result: {
|
|
5472
6181
|
tool_call_id: tc.id,
|
|
5473
6182
|
name: tc.function.name,
|
|
@@ -5480,10 +6189,13 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5480
6189
|
}
|
|
5481
6190
|
if (codeMode && CODE_MODE_REDIRECT_TOOLS.has(tc.function.name) && codeModeRedirects < MAX_CODE_MODE_REDIRECTS) {
|
|
5482
6191
|
codeModeRedirects++;
|
|
6192
|
+
noteCodeModeRedirect();
|
|
5483
6193
|
items.push({
|
|
5484
6194
|
kind: "blocked",
|
|
5485
6195
|
tc,
|
|
5486
6196
|
loopSignature,
|
|
6197
|
+
errorCode: "code_mode_redirect",
|
|
6198
|
+
redirected: true,
|
|
5487
6199
|
result: { tool_call_id: tc.id, name: tc.function.name, content: codeModeRedirectMessage(tc.function.name), ok: false }
|
|
5488
6200
|
});
|
|
5489
6201
|
continue;
|
|
@@ -5500,6 +6212,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5500
6212
|
kind: "blocked",
|
|
5501
6213
|
tc,
|
|
5502
6214
|
loopSignature,
|
|
6215
|
+
errorCode: "web_fetch_budget",
|
|
5503
6216
|
result: { tool_call_id: tc.id, name: "web_fetch", content: warning, ok: false, guardrail: true }
|
|
5504
6217
|
});
|
|
5505
6218
|
continue;
|
|
@@ -5520,6 +6233,8 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5520
6233
|
{ id: it.tc.id, name: it.tc.function.name, arguments: it.tc.function.arguments },
|
|
5521
6234
|
batchAskPermission,
|
|
5522
6235
|
{
|
|
6236
|
+
trace,
|
|
6237
|
+
turnId,
|
|
5523
6238
|
cwd: opts2.cwd,
|
|
5524
6239
|
signal: opts2.signal,
|
|
5525
6240
|
onTasks: wrappedOnTasks,
|
|
@@ -5562,6 +6277,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5562
6277
|
}
|
|
5563
6278
|
for (const it of items) {
|
|
5564
6279
|
if (it.kind === "blocked") {
|
|
6280
|
+
traceBlocked(it.tc, it.result, it.errorCode, it.redirected === true);
|
|
5565
6281
|
toolResults.push(it.result);
|
|
5566
6282
|
opts2.messages.push({
|
|
5567
6283
|
role: "tool",
|
|
@@ -5697,6 +6413,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5697
6413
|
content: `Tool ${tc.function.name} is not available under this turn's policy. Continue without it or ask the user to enable it.`,
|
|
5698
6414
|
ok: false
|
|
5699
6415
|
};
|
|
6416
|
+
traceBlocked(tc, unavailableResult, "unavailable");
|
|
5700
6417
|
toolResults.push(unavailableResult);
|
|
5701
6418
|
opts2.messages.push({
|
|
5702
6419
|
role: "tool",
|
|
@@ -5720,6 +6437,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5720
6437
|
ok: false,
|
|
5721
6438
|
guardrail: true
|
|
5722
6439
|
};
|
|
6440
|
+
traceBlocked(tc, loopResult, "loop_guardrail");
|
|
5723
6441
|
toolResults.push(loopResult);
|
|
5724
6442
|
opts2.messages.push({
|
|
5725
6443
|
role: "tool",
|
|
@@ -5748,6 +6466,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5748
6466
|
ok: false,
|
|
5749
6467
|
guardrail: true
|
|
5750
6468
|
};
|
|
6469
|
+
traceBlocked(tc, budgetResult, "web_fetch_budget");
|
|
5751
6470
|
toolResults.push(budgetResult);
|
|
5752
6471
|
opts2.messages.push({
|
|
5753
6472
|
role: "tool",
|
|
@@ -5770,6 +6489,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5770
6489
|
ok: false,
|
|
5771
6490
|
guardrail: true
|
|
5772
6491
|
};
|
|
6492
|
+
traceBlocked(tc, sessionCapResult, "web_fetch_budget");
|
|
5773
6493
|
toolResults.push(sessionCapResult);
|
|
5774
6494
|
opts2.messages.push({
|
|
5775
6495
|
role: "tool",
|
|
@@ -5791,12 +6511,39 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5791
6511
|
if (codeMode && tc.function.name === "execute_code") {
|
|
5792
6512
|
const args = JSON.parse(tc.function.arguments || "{}");
|
|
5793
6513
|
const code = args.code || "";
|
|
6514
|
+
const sandboxStartedAt = performance.now();
|
|
6515
|
+
if (trace.enabled) {
|
|
6516
|
+
trace.emit(
|
|
6517
|
+
"tool_call",
|
|
6518
|
+
{
|
|
6519
|
+
tool_call_id: tc.id,
|
|
6520
|
+
name: "execute_code",
|
|
6521
|
+
args_blob: trace.blob(tc.function.arguments) ?? "",
|
|
6522
|
+
...tc.function.arguments.length <= 2048 ? { args_inline: parseArgsObject(tc.function.arguments) } : {},
|
|
6523
|
+
needs_permission: false,
|
|
6524
|
+
code_mode_redirected: false
|
|
6525
|
+
},
|
|
6526
|
+
turnId
|
|
6527
|
+
);
|
|
6528
|
+
}
|
|
5794
6529
|
const sandboxResult = await runInSandbox({
|
|
5795
6530
|
code,
|
|
5796
6531
|
tools: sandboxTools,
|
|
5797
6532
|
executor: opts2.executor,
|
|
5798
6533
|
askPermission: opts2.callbacks.askPermission,
|
|
5799
|
-
ctx: {
|
|
6534
|
+
ctx: {
|
|
6535
|
+
cwd: opts2.cwd,
|
|
6536
|
+
signal: opts2.signal,
|
|
6537
|
+
onTasks: wrappedOnTasks,
|
|
6538
|
+
onPlanOptions: opts2.callbacks.onPlanOptions,
|
|
6539
|
+
coauthor: opts2.coauthor,
|
|
6540
|
+
memoryManager: opts2.memoryManager,
|
|
6541
|
+
sessionId: opts2.sessionId,
|
|
6542
|
+
githubToken: opts2.githubToken,
|
|
6543
|
+
trace,
|
|
6544
|
+
turnId,
|
|
6545
|
+
codeModeParentToolCallId: tc.id
|
|
6546
|
+
},
|
|
5800
6547
|
timeoutMs: 3e4,
|
|
5801
6548
|
memoryLimitMB: 128
|
|
5802
6549
|
});
|
|
@@ -5819,6 +6566,7 @@ Not in this API \u2014 call these as separate tools instead: ${directTools.map((
|
|
|
5819
6566
|
|
|
5820
6567
|
Output:
|
|
5821
6568
|
${sandboxResult.output}` : sandboxResult.output;
|
|
6569
|
+
const sandboxRawContent = resultContent;
|
|
5822
6570
|
if (resultContent.length > MAX_TOOL_CONTENT_CHARS) {
|
|
5823
6571
|
const rawBytes = resultContent.length;
|
|
5824
6572
|
resultContent = resultContent.slice(0, MAX_TOOL_CONTENT_CHARS) + `
|
|
@@ -5837,6 +6585,24 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
5837
6585
|
content: resultContent,
|
|
5838
6586
|
ok: !sandboxResult.error
|
|
5839
6587
|
};
|
|
6588
|
+
if (trace.enabled) {
|
|
6589
|
+
const rawBlob = trace.blob(sandboxRawContent) ?? "";
|
|
6590
|
+
trace.emit(
|
|
6591
|
+
"tool_result",
|
|
6592
|
+
{
|
|
6593
|
+
tool_call_id: tc.id,
|
|
6594
|
+
name: "execute_code",
|
|
6595
|
+
ok: result2.ok,
|
|
6596
|
+
...sandboxResult.error ? { error_code: "sandbox_error" } : {},
|
|
6597
|
+
raw_blob: rawBlob,
|
|
6598
|
+
raw_bytes: Buffer.byteLength(sandboxRawContent, "utf8"),
|
|
6599
|
+
reduced_blob: sandboxRawContent === resultContent ? rawBlob : trace.blob(resultContent) ?? "",
|
|
6600
|
+
reduced_bytes: Buffer.byteLength(resultContent, "utf8"),
|
|
6601
|
+
duration_ms: Math.round(performance.now() - sandboxStartedAt)
|
|
6602
|
+
},
|
|
6603
|
+
turnId
|
|
6604
|
+
);
|
|
6605
|
+
}
|
|
5840
6606
|
toolResults.push(result2);
|
|
5841
6607
|
opts2.messages.push({
|
|
5842
6608
|
role: "tool",
|
|
@@ -5849,8 +6615,10 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
5849
6615
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
5850
6616
|
} else if (codeMode && CODE_MODE_REDIRECT_TOOLS.has(tc.function.name) && codeModeRedirects < MAX_CODE_MODE_REDIRECTS) {
|
|
5851
6617
|
codeModeRedirects++;
|
|
6618
|
+
noteCodeModeRedirect();
|
|
5852
6619
|
const msg = codeModeRedirectMessage(tc.function.name);
|
|
5853
6620
|
const redirectResult = { tool_call_id: tc.id, name: tc.function.name, content: msg, ok: false };
|
|
6621
|
+
traceBlocked(tc, redirectResult, "code_mode_redirect", true);
|
|
5854
6622
|
toolResults.push(redirectResult);
|
|
5855
6623
|
opts2.messages.push({ role: "tool", tool_call_id: tc.id, content: msg, name: tc.function.name });
|
|
5856
6624
|
opts2.callbacks.onToolResult?.(redirectResult);
|
|
@@ -5861,6 +6629,8 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
5861
6629
|
{ id: tc.id, name: tc.function.name, arguments: tc.function.arguments },
|
|
5862
6630
|
opts2.callbacks.askPermission,
|
|
5863
6631
|
{
|
|
6632
|
+
trace,
|
|
6633
|
+
turnId,
|
|
5864
6634
|
cwd: opts2.cwd,
|
|
5865
6635
|
signal: opts2.signal,
|
|
5866
6636
|
onTasks: wrappedOnTasks,
|
|
@@ -5929,6 +6699,7 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
5929
6699
|
condition: result2.waitRequest.condition,
|
|
5930
6700
|
wakeAt: result2.waitRequest.wakeAt
|
|
5931
6701
|
});
|
|
6702
|
+
tr.endReason = "needs_input";
|
|
5932
6703
|
try {
|
|
5933
6704
|
opts2.callbacks.onRunYield?.(result2.waitRequest);
|
|
5934
6705
|
} catch (error) {
|
|
@@ -6087,7 +6858,7 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
6087
6858
|
role: "system",
|
|
6088
6859
|
content: "Every tool call in your last step was blocked because you kept repeating the same calls with identical arguments. Do not repeat them. Either take a genuinely different approach (different tools, arguments, or files), or, if you already have enough information, stop calling tools and give your final answer."
|
|
6089
6860
|
});
|
|
6090
|
-
|
|
6861
|
+
notifyGuardrail({
|
|
6091
6862
|
kind: "loop_recovery",
|
|
6092
6863
|
message: "Loop guardrail: repeated tool calls were blocked \u2014 asked the agent to change approach."
|
|
6093
6864
|
});
|
|
@@ -6098,7 +6869,7 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
6098
6869
|
role: "system",
|
|
6099
6870
|
content: "You are still repeating blocked tool calls after being asked to change approach, so this turn is ending. Do not call any more tools. Summarize what you accomplished, what is blocking you, and what the user could do next."
|
|
6100
6871
|
});
|
|
6101
|
-
|
|
6872
|
+
notifyGuardrail({
|
|
6102
6873
|
kind: "loop_stopped",
|
|
6103
6874
|
message: "Loop guardrail: the agent kept repeating blocked tool calls \u2014 ending the turn with a summary."
|
|
6104
6875
|
});
|
|
@@ -6159,6 +6930,8 @@ var init_loop = __esm({
|
|
|
6159
6930
|
init_context_budget();
|
|
6160
6931
|
init_turn_directive();
|
|
6161
6932
|
init_completion_check();
|
|
6933
|
+
init_recorder();
|
|
6934
|
+
init_git_delta();
|
|
6162
6935
|
MAX_LOOP_RECOVERIES = 1;
|
|
6163
6936
|
BudgetExhaustedError = class extends Error {
|
|
6164
6937
|
constructor(message2 = "Cumulative input token budget exhausted") {
|
|
@@ -6214,10 +6987,10 @@ var init_pricing = __esm({
|
|
|
6214
6987
|
// src/util/atomic-file.ts
|
|
6215
6988
|
import { mkdir as mkdir6, rename, rm, stat as stat3, writeFile as writeFile5 } from "fs/promises";
|
|
6216
6989
|
import { dirname as dirname6 } from "path";
|
|
6217
|
-
import { randomUUID } from "crypto";
|
|
6990
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
6218
6991
|
async function writeFileAtomic(path, data) {
|
|
6219
6992
|
await mkdir6(dirname6(path), { recursive: true });
|
|
6220
|
-
const tmp = `${path}.${process.pid}.${
|
|
6993
|
+
const tmp = `${path}.${process.pid}.${randomUUID2().slice(0, 8)}.tmp`;
|
|
6221
6994
|
try {
|
|
6222
6995
|
await writeFile5(tmp, data, "utf8");
|
|
6223
6996
|
await rename(tmp, path);
|
|
@@ -6272,19 +7045,19 @@ var init_atomic_file = __esm({
|
|
|
6272
7045
|
|
|
6273
7046
|
// src/usage-tracker.ts
|
|
6274
7047
|
import { readFile as readFile5, rename as rename2 } from "fs/promises";
|
|
6275
|
-
import { homedir as
|
|
6276
|
-
import { join as
|
|
7048
|
+
import { homedir as homedir9 } from "os";
|
|
7049
|
+
import { join as join15 } from "path";
|
|
6277
7050
|
import { EventEmitter } from "events";
|
|
6278
|
-
import { randomUUID as
|
|
7051
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6279
7052
|
function usageDir() {
|
|
6280
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
6281
|
-
return
|
|
7053
|
+
const xdg = process.env.XDG_DATA_HOME || join15(homedir9(), ".local", "share");
|
|
7054
|
+
return join15(xdg, "kimiflare");
|
|
6282
7055
|
}
|
|
6283
7056
|
function usagePath() {
|
|
6284
|
-
return
|
|
7057
|
+
return join15(usageDir(), "usage.json");
|
|
6285
7058
|
}
|
|
6286
7059
|
function historyPath() {
|
|
6287
|
-
return
|
|
7060
|
+
return join15(usageDir(), "history.jsonl");
|
|
6288
7061
|
}
|
|
6289
7062
|
function today() {
|
|
6290
7063
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -6404,7 +7177,7 @@ async function recordUsage(sessionId, usage, lookup, model) {
|
|
|
6404
7177
|
);
|
|
6405
7178
|
const estimatedCost = cost.total;
|
|
6406
7179
|
const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
6407
|
-
const turnId =
|
|
7180
|
+
const turnId = randomUUID3();
|
|
6408
7181
|
const generationId = lookup?.meta.generationId;
|
|
6409
7182
|
const inlineCost = typeof usage.cost === "number" && Number.isFinite(usage.cost) ? usage.cost : void 0;
|
|
6410
7183
|
await withLock(async () => {
|
|
@@ -6705,12 +7478,41 @@ var init_tool_error = __esm({
|
|
|
6705
7478
|
}
|
|
6706
7479
|
});
|
|
6707
7480
|
|
|
7481
|
+
// src/trace/verification.ts
|
|
7482
|
+
function segment(alternatives) {
|
|
7483
|
+
return new RegExp(`${SEG}(?:${alternatives})(?:\\s|$)`);
|
|
7484
|
+
}
|
|
7485
|
+
function classifyVerification(command) {
|
|
7486
|
+
const trimmed = command.trim();
|
|
7487
|
+
if (!trimmed) return null;
|
|
7488
|
+
for (const [category, re] of TABLE) {
|
|
7489
|
+
if (re.test(trimmed)) return category;
|
|
7490
|
+
}
|
|
7491
|
+
return null;
|
|
7492
|
+
}
|
|
7493
|
+
var SEG, TABLE;
|
|
7494
|
+
var init_verification = __esm({
|
|
7495
|
+
"src/trace/verification.ts"() {
|
|
7496
|
+
"use strict";
|
|
7497
|
+
SEG = String.raw`(?:^|[;|(]\s*|&&\s*|\|\|\s*)(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*(?:npx\s+|pnpm\s+exec\s+|pnpm\s+dlx\s+|yarn\s+|bunx\s+|bun\s+run\s+|(?:\.\/)?node_modules\/\.bin\/)?`;
|
|
7498
|
+
TABLE = [
|
|
7499
|
+
[
|
|
7500
|
+
"test",
|
|
7501
|
+
segment(String.raw`npm\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|yarn\s+(?:run\s+)?test|tsx\s+--test|node\s+--test|vitest|jest|pytest|go\s+test|cargo\s+test`)
|
|
7502
|
+
],
|
|
7503
|
+
["lint", segment(String.raw`eslint|ruff|golangci-lint|npm\s+run\s+lint|pnpm\s+(?:run\s+)?lint|yarn\s+(?:run\s+)?lint`)],
|
|
7504
|
+
["typecheck", segment(String.raw`tsc|mypy|pyright|npm\s+run\s+typecheck|pnpm\s+(?:run\s+)?typecheck|yarn\s+(?:run\s+)?typecheck`)],
|
|
7505
|
+
["build", segment(String.raw`npm\s+run\s+build|tsup|cargo\s+build|go\s+build|pnpm\s+(?:run\s+)?build|yarn\s+(?:run\s+)?build`)]
|
|
7506
|
+
];
|
|
7507
|
+
}
|
|
7508
|
+
});
|
|
7509
|
+
|
|
6708
7510
|
// src/util/paths.ts
|
|
6709
7511
|
import { resolve, isAbsolute, relative, sep } from "path";
|
|
6710
|
-
import { homedir as
|
|
7512
|
+
import { homedir as homedir10 } from "os";
|
|
6711
7513
|
function resolvePath(cwd, input) {
|
|
6712
7514
|
if (input.startsWith("~/") || input === "~") {
|
|
6713
|
-
return resolve(
|
|
7515
|
+
return resolve(homedir10(), input === "~" ? "." : input.slice(2));
|
|
6714
7516
|
}
|
|
6715
7517
|
return isAbsolute(input) ? input : resolve(cwd, input);
|
|
6716
7518
|
}
|
|
@@ -6737,7 +7539,7 @@ function collapsePath(input, cwd, maxLen = 40) {
|
|
|
6737
7539
|
function collapsePathsInText(s, cwd, maxLen = 40) {
|
|
6738
7540
|
return s.replace(/([~/][^\s"',)}\]]+)/g, (match) => collapsePath(match, cwd, maxLen));
|
|
6739
7541
|
}
|
|
6740
|
-
var
|
|
7542
|
+
var init_paths2 = __esm({
|
|
6741
7543
|
"src/util/paths.ts"() {
|
|
6742
7544
|
"use strict";
|
|
6743
7545
|
}
|
|
@@ -6794,7 +7596,7 @@ var MAX_BYTES, MAX_STREAM_BYTES, readTool;
|
|
|
6794
7596
|
var init_read = __esm({
|
|
6795
7597
|
"src/tools/read.ts"() {
|
|
6796
7598
|
"use strict";
|
|
6797
|
-
|
|
7599
|
+
init_paths2();
|
|
6798
7600
|
MAX_BYTES = 2 * 1024 * 1024;
|
|
6799
7601
|
MAX_STREAM_BYTES = 50 * 1024 * 1024;
|
|
6800
7602
|
readTool = {
|
|
@@ -6845,7 +7647,7 @@ var writeTool;
|
|
|
6845
7647
|
var init_write = __esm({
|
|
6846
7648
|
"src/tools/write.ts"() {
|
|
6847
7649
|
"use strict";
|
|
6848
|
-
|
|
7650
|
+
init_paths2();
|
|
6849
7651
|
writeTool = {
|
|
6850
7652
|
name: "write",
|
|
6851
7653
|
description: "Create a file or overwrite an existing one with the given contents. Prompts the user for permission first and shows a diff preview.",
|
|
@@ -6896,7 +7698,7 @@ var editTool;
|
|
|
6896
7698
|
var init_edit = __esm({
|
|
6897
7699
|
"src/tools/edit.ts"() {
|
|
6898
7700
|
"use strict";
|
|
6899
|
-
|
|
7701
|
+
init_paths2();
|
|
6900
7702
|
editTool = {
|
|
6901
7703
|
name: "edit",
|
|
6902
7704
|
description: "Replace an exact string in a file. If replace_all is false (default), the old_string must appear exactly once or the call fails. Prompts the user for permission first and shows a diff preview.",
|
|
@@ -6937,7 +7739,7 @@ var init_edit = __esm({
|
|
|
6937
7739
|
// src/tools/bash.ts
|
|
6938
7740
|
import { spawn } from "child_process";
|
|
6939
7741
|
import { tmpdir, platform as platform2 } from "os";
|
|
6940
|
-
import { join as
|
|
7742
|
+
import { join as join16 } from "path";
|
|
6941
7743
|
function getShellCommand(override) {
|
|
6942
7744
|
const raw = override?.trim();
|
|
6943
7745
|
if (raw && raw !== "auto") {
|
|
@@ -7139,7 +7941,7 @@ function injectCoauthor(command, coauthor) {
|
|
|
7139
7941
|
if (movesHeadOnly) return unchanged;
|
|
7140
7942
|
const env2 = {
|
|
7141
7943
|
[COAUTHOR_TRAILER_ENV]: trailer,
|
|
7142
|
-
[COAUTHOR_MSG_ENV]:
|
|
7944
|
+
[COAUTHOR_MSG_ENV]: join16(tmpdir(), `kf-coauthor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`)
|
|
7143
7945
|
};
|
|
7144
7946
|
if (createsCommit || isRebaseContinue) {
|
|
7145
7947
|
return { command: `(${command}) && { ${AMEND_BLOCK}
|
|
@@ -7232,7 +8034,8 @@ ${stderr}`
|
|
|
7232
8034
|
resolve15({
|
|
7233
8035
|
content: raw,
|
|
7234
8036
|
rawBytes: Buffer.byteLength(raw, "utf8"),
|
|
7235
|
-
reducedBytes: Buffer.byteLength(raw, "utf8")
|
|
8037
|
+
reducedBytes: Buffer.byteLength(raw, "utf8"),
|
|
8038
|
+
meta: { exitCode: code, timedOut: killedByTimeout }
|
|
7236
8039
|
});
|
|
7237
8040
|
});
|
|
7238
8041
|
});
|
|
@@ -7280,7 +8083,7 @@ var init_bash = __esm({
|
|
|
7280
8083
|
|
|
7281
8084
|
// src/util/glob.ts
|
|
7282
8085
|
import { readdir as readdir3, lstat, realpath } from "fs/promises";
|
|
7283
|
-
import { join as
|
|
8086
|
+
import { join as join17, relative as relative2, resolve as resolve2 } from "path";
|
|
7284
8087
|
function parsePattern(pattern) {
|
|
7285
8088
|
const parts = pattern.split(/\//g);
|
|
7286
8089
|
return parts.map((p) => {
|
|
@@ -7321,8 +8124,8 @@ function globToRegex(glob2) {
|
|
|
7321
8124
|
re += "$";
|
|
7322
8125
|
return new RegExp(re);
|
|
7323
8126
|
}
|
|
7324
|
-
function matchSegment(
|
|
7325
|
-
return globToRegex(pattern).test(
|
|
8127
|
+
function matchSegment(segment2, pattern) {
|
|
8128
|
+
return globToRegex(pattern).test(segment2);
|
|
7326
8129
|
}
|
|
7327
8130
|
function shouldIgnore(relativePath, ignorePatterns) {
|
|
7328
8131
|
for (const pat of ignorePatterns) {
|
|
@@ -7389,7 +8192,7 @@ async function* walk(root, pattern, options) {
|
|
|
7389
8192
|
if (!dot && name.startsWith(".")) continue;
|
|
7390
8193
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
7391
8194
|
if (!matched) continue;
|
|
7392
|
-
const childPath =
|
|
8195
|
+
const childPath = join17(dirPath, name);
|
|
7393
8196
|
const childRel = [...relativeParts, name];
|
|
7394
8197
|
const childRelStr = childRel.join("/");
|
|
7395
8198
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -7414,7 +8217,7 @@ async function* walk(root, pattern, options) {
|
|
|
7414
8217
|
if (!dot && name.startsWith(".")) continue;
|
|
7415
8218
|
const matched = seg.type === "literal" ? seg.value === name : matchSegment(name, seg.value);
|
|
7416
8219
|
if (!matched) continue;
|
|
7417
|
-
const childPath =
|
|
8220
|
+
const childPath = join17(dirPath, name);
|
|
7418
8221
|
const childRel = [...relativeParts, name];
|
|
7419
8222
|
const childRelStr = childRel.join("/");
|
|
7420
8223
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -7456,7 +8259,7 @@ async function* walk(root, pattern, options) {
|
|
|
7456
8259
|
const name = String(ent.name);
|
|
7457
8260
|
if (name === "." || name === "..") continue;
|
|
7458
8261
|
if (!dot && name.startsWith(".")) continue;
|
|
7459
|
-
const childPath =
|
|
8262
|
+
const childPath = join17(dirPath, name);
|
|
7460
8263
|
const childRel = [...relativeParts, name];
|
|
7461
8264
|
const childRelStr = childRel.join("/");
|
|
7462
8265
|
if (shouldIgnore(childRelStr, ignorePatterns)) continue;
|
|
@@ -7550,7 +8353,7 @@ var globTool;
|
|
|
7550
8353
|
var init_glob2 = __esm({
|
|
7551
8354
|
"src/tools/glob.ts"() {
|
|
7552
8355
|
"use strict";
|
|
7553
|
-
|
|
8356
|
+
init_paths2();
|
|
7554
8357
|
init_glob();
|
|
7555
8358
|
globTool = {
|
|
7556
8359
|
name: "glob",
|
|
@@ -7601,8 +8404,8 @@ var init_glob2 = __esm({
|
|
|
7601
8404
|
});
|
|
7602
8405
|
|
|
7603
8406
|
// src/tools/grep.ts
|
|
7604
|
-
import { execFile } from "child_process";
|
|
7605
|
-
import { promisify } from "util";
|
|
8407
|
+
import { execFile as execFile2 } from "child_process";
|
|
8408
|
+
import { promisify as promisify2 } from "util";
|
|
7606
8409
|
import { readFile as readFile9 } from "fs/promises";
|
|
7607
8410
|
async function hasRipgrep() {
|
|
7608
8411
|
if (cachedHasRg !== null) return cachedHasRg;
|
|
@@ -7678,9 +8481,9 @@ var pExecFile, cachedHasRg, grepTool;
|
|
|
7678
8481
|
var init_grep = __esm({
|
|
7679
8482
|
"src/tools/grep.ts"() {
|
|
7680
8483
|
"use strict";
|
|
7681
|
-
|
|
8484
|
+
init_paths2();
|
|
7682
8485
|
init_glob();
|
|
7683
|
-
pExecFile =
|
|
8486
|
+
pExecFile = promisify2(execFile2);
|
|
7684
8487
|
cachedHasRg = null;
|
|
7685
8488
|
grepTool = {
|
|
7686
8489
|
name: "grep",
|
|
@@ -8224,7 +9027,7 @@ __export(changelog_image_exports, {
|
|
|
8224
9027
|
});
|
|
8225
9028
|
import { readFile as readFile10 } from "fs/promises";
|
|
8226
9029
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
8227
|
-
import { join as
|
|
9030
|
+
import { join as join18 } from "path";
|
|
8228
9031
|
async function githubFetch2(path, token) {
|
|
8229
9032
|
const controller = new AbortController();
|
|
8230
9033
|
const timer3 = setTimeout(() => controller.abort(), TIMEOUT_MS4);
|
|
@@ -8255,7 +9058,7 @@ function escapeXml(str) {
|
|
|
8255
9058
|
}
|
|
8256
9059
|
async function loadLogoBase64() {
|
|
8257
9060
|
try {
|
|
8258
|
-
const buf = await readFile10(
|
|
9061
|
+
const buf = await readFile10(join18(process.cwd(), "docs", "logo.png"));
|
|
8259
9062
|
return `data:image/png;base64,${buf.toString("base64")}`;
|
|
8260
9063
|
} catch {
|
|
8261
9064
|
return null;
|
|
@@ -8563,7 +9366,7 @@ Format your response as plain text bullet points, one per line, starting with "\
|
|
|
8563
9366
|
// src/tools/browser.ts
|
|
8564
9367
|
import { mkdir as mkdir8 } from "fs/promises";
|
|
8565
9368
|
import { tmpdir as tmpdir2 } from "os";
|
|
8566
|
-
import { join as
|
|
9369
|
+
import { join as join19, dirname as dirname8 } from "path";
|
|
8567
9370
|
async function autoScroll(page) {
|
|
8568
9371
|
await page.evaluate(async () => {
|
|
8569
9372
|
await new Promise((resolve15) => {
|
|
@@ -8639,7 +9442,7 @@ var init_browser = __esm({
|
|
|
8639
9442
|
}
|
|
8640
9443
|
let screenshotPath;
|
|
8641
9444
|
if (args.screenshot) {
|
|
8642
|
-
screenshotPath =
|
|
9445
|
+
screenshotPath = join19(tmpdir2(), `kimiflare-browser-${Date.now()}.png`);
|
|
8643
9446
|
await mkdir8(dirname8(screenshotPath), { recursive: true });
|
|
8644
9447
|
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
8645
9448
|
}
|
|
@@ -8893,13 +9696,13 @@ var init_memory = __esm({
|
|
|
8893
9696
|
});
|
|
8894
9697
|
|
|
8895
9698
|
// src/tools/hotcell-snapshot.ts
|
|
8896
|
-
import { execFile as
|
|
9699
|
+
import { execFile as execFile3 } from "child_process";
|
|
8897
9700
|
import { mkdtemp, rm as rm2 } from "fs/promises";
|
|
8898
9701
|
import { tmpdir as tmpdir3 } from "os";
|
|
8899
|
-
import { join as
|
|
8900
|
-
import { promisify as
|
|
9702
|
+
import { join as join20 } from "path";
|
|
9703
|
+
import { promisify as promisify3 } from "util";
|
|
8901
9704
|
async function git(args, cwd, env2) {
|
|
8902
|
-
const { stdout } = await
|
|
9705
|
+
const { stdout } = await execFileAsync2("git", args, {
|
|
8903
9706
|
cwd,
|
|
8904
9707
|
env: env2 ? { ...process.env, ...env2 } : process.env,
|
|
8905
9708
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -8908,7 +9711,7 @@ async function git(args, cwd, env2) {
|
|
|
8908
9711
|
return stdout.toString("utf8");
|
|
8909
9712
|
}
|
|
8910
9713
|
async function gitBuffer(args, cwd) {
|
|
8911
|
-
const { stdout } = await
|
|
9714
|
+
const { stdout } = await execFileAsync2("git", args, { cwd, maxBuffer: 64 * 1024 * 1024, encoding: "buffer" });
|
|
8912
9715
|
return stdout;
|
|
8913
9716
|
}
|
|
8914
9717
|
async function originBranchesContaining(commit, cwd) {
|
|
@@ -8944,9 +9747,9 @@ async function getRepositorySnapshot(cwd) {
|
|
|
8944
9747
|
if (!ref) {
|
|
8945
9748
|
throw new Error("Could not find an origin branch containing the base commit. Run git fetch, then retry.");
|
|
8946
9749
|
}
|
|
8947
|
-
const scratch = await mkdtemp(
|
|
9750
|
+
const scratch = await mkdtemp(join20(tmpdir3(), "autopilot-snapshot-"));
|
|
8948
9751
|
try {
|
|
8949
|
-
const env2 = { GIT_INDEX_FILE:
|
|
9752
|
+
const env2 = { GIT_INDEX_FILE: join20(scratch, "index") };
|
|
8950
9753
|
await git(["read-tree", "HEAD"], root, env2);
|
|
8951
9754
|
await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
|
|
8952
9755
|
const tree = (await git(["write-tree"], root, env2)).trim();
|
|
@@ -8971,9 +9774,9 @@ async function getRepositorySnapshot(cwd) {
|
|
|
8971
9774
|
async function getWorkingTreeArchive(cwd, limitBytes = MAX_ARCHIVE_BYTES) {
|
|
8972
9775
|
const root = (await git(["rev-parse", "--show-toplevel"], cwd).catch(() => "")).trim();
|
|
8973
9776
|
if (!root) throw new Error("Subagents need to run inside a Git repository.");
|
|
8974
|
-
const scratch = await mkdtemp(
|
|
9777
|
+
const scratch = await mkdtemp(join20(tmpdir3(), "autopilot-archive-"));
|
|
8975
9778
|
try {
|
|
8976
|
-
const env2 = { GIT_INDEX_FILE:
|
|
9779
|
+
const env2 = { GIT_INDEX_FILE: join20(scratch, "index") };
|
|
8977
9780
|
const hasHead = await git(["rev-parse", "--verify", "-q", "HEAD"], root).then(() => true, () => false);
|
|
8978
9781
|
await git(hasHead ? ["read-tree", "HEAD"] : ["read-tree", "--empty"], root, env2);
|
|
8979
9782
|
await git(["add", "-A", "--", ".", ...SECRET_EXCLUDES], root, env2);
|
|
@@ -8995,11 +9798,11 @@ function chunkPayload(base64, chunkSize = PAYLOAD_CHUNK_CHARS) {
|
|
|
8995
9798
|
for (let i = 0; i < base64.length; i += chunkSize) chunks.push(base64.slice(i, i + chunkSize));
|
|
8996
9799
|
return chunks;
|
|
8997
9800
|
}
|
|
8998
|
-
var
|
|
9801
|
+
var execFileAsync2, MAX_SNAPSHOT_PATCH_BYTES, MAX_ARCHIVE_BYTES, SECRET_EXCLUDES, PAYLOAD_CHUNK_CHARS;
|
|
8999
9802
|
var init_hotcell_snapshot = __esm({
|
|
9000
9803
|
"src/tools/hotcell-snapshot.ts"() {
|
|
9001
9804
|
"use strict";
|
|
9002
|
-
|
|
9805
|
+
execFileAsync2 = promisify3(execFile3);
|
|
9003
9806
|
MAX_SNAPSHOT_PATCH_BYTES = 4 * 1024 * 1024;
|
|
9004
9807
|
MAX_ARCHIVE_BYTES = 24 * 1024 * 1024;
|
|
9005
9808
|
SECRET_EXCLUDES = [
|
|
@@ -9022,11 +9825,11 @@ var init_hotcell_snapshot = __esm({
|
|
|
9022
9825
|
|
|
9023
9826
|
// src/tools/hotcell-worker-cache.ts
|
|
9024
9827
|
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile10 } from "fs/promises";
|
|
9025
|
-
import { homedir as
|
|
9026
|
-
import { dirname as dirname9, join as
|
|
9828
|
+
import { homedir as homedir11 } from "os";
|
|
9829
|
+
import { dirname as dirname9, join as join21 } from "path";
|
|
9027
9830
|
function workerCachePath() {
|
|
9028
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
9029
|
-
return
|
|
9831
|
+
const xdg = process.env.XDG_CONFIG_HOME || join21(homedir11(), ".config");
|
|
9832
|
+
return join21(xdg, "kimiflare", "hotcell-worker-cache.json");
|
|
9030
9833
|
}
|
|
9031
9834
|
async function readCache2() {
|
|
9032
9835
|
try {
|
|
@@ -9098,8 +9901,8 @@ var init_hotcell_worker_cache = __esm({
|
|
|
9098
9901
|
|
|
9099
9902
|
// src/tools/hotcell-worker.ts
|
|
9100
9903
|
import { spawn as spawn2 } from "child_process";
|
|
9101
|
-
import { promisify as
|
|
9102
|
-
import { execFile as
|
|
9904
|
+
import { promisify as promisify4 } from "util";
|
|
9905
|
+
import { execFile as execFile4 } from "child_process";
|
|
9103
9906
|
import { resolve as resolve3 } from "path";
|
|
9104
9907
|
async function runHotcellWorker(options) {
|
|
9105
9908
|
const workerId = `hotcell-${crypto.randomUUID().slice(0, 8)}`;
|
|
@@ -9505,7 +10308,7 @@ function releaseSlot() {
|
|
|
9505
10308
|
runningWorkers = Math.max(0, runningWorkers - 1);
|
|
9506
10309
|
for (const wake of workerQueue.slice()) wake();
|
|
9507
10310
|
}
|
|
9508
|
-
var
|
|
10311
|
+
var execFileAsync3, MAX_OUTPUT_BYTES, MAX_PROMPT_CHARS, DEFAULT_CELL_TIMEOUT_MS, DEFAULT_SETUP_TIMEOUT_MS, WORKER_BIN, PACKAGE_SPEC, LOCATE_REPO_ROOT, READ_REPO_ROOT, REPO_ASIDE, SNAPSHOT_PREFIX, ARCHIVE_ROOT, MAX_PARALLEL_WORKERS, MIN_WORKER_INPUT_TOKENS, MAX_WORKER_INPUT_TOKENS, DEFAULT_WORKER_INPUT_TOKENS, INPUT_SHARE_OF_BUDGET, MAX_REPORT_FINDINGS, MAX_REPORT_SUMMARY_CHARS, MAX_REPORT_LIST_ITEMS, runningWorkers, workerQueue, WORKER_REPORT_INSTRUCTIONS;
|
|
9509
10312
|
var init_hotcell_worker = __esm({
|
|
9510
10313
|
"src/tools/hotcell-worker.ts"() {
|
|
9511
10314
|
"use strict";
|
|
@@ -9514,7 +10317,7 @@ var init_hotcell_worker = __esm({
|
|
|
9514
10317
|
init_registry();
|
|
9515
10318
|
init_hotcell_snapshot();
|
|
9516
10319
|
init_hotcell_worker_cache();
|
|
9517
|
-
|
|
10320
|
+
execFileAsync3 = promisify4(execFile4);
|
|
9518
10321
|
MAX_OUTPUT_BYTES = 1e6;
|
|
9519
10322
|
MAX_PROMPT_CHARS = 4e4;
|
|
9520
10323
|
DEFAULT_CELL_TIMEOUT_MS = 3e5;
|
|
@@ -9636,11 +10439,11 @@ var init_worker_registry = __esm({
|
|
|
9636
10439
|
|
|
9637
10440
|
// src/tools/subagent-stats.ts
|
|
9638
10441
|
import { appendFile as appendFile2, mkdir as mkdir10, readFile as readFile12 } from "fs/promises";
|
|
9639
|
-
import { homedir as
|
|
9640
|
-
import { dirname as dirname10, join as
|
|
10442
|
+
import { homedir as homedir12 } from "os";
|
|
10443
|
+
import { dirname as dirname10, join as join22 } from "path";
|
|
9641
10444
|
function subagentStatsPath() {
|
|
9642
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
9643
|
-
return
|
|
10445
|
+
const xdg = process.env.XDG_DATA_HOME || join22(homedir12(), ".local", "share");
|
|
10446
|
+
return join22(xdg, "kimiflare", "subagents.jsonl");
|
|
9644
10447
|
}
|
|
9645
10448
|
async function recordSubagentEvent(event) {
|
|
9646
10449
|
const path = subagentStatsPath();
|
|
@@ -9866,16 +10669,29 @@ var init_subagent = __esm({
|
|
|
9866
10669
|
}
|
|
9867
10670
|
const handle = workerRegistry.start(args.mission, model, ctx.signal);
|
|
9868
10671
|
const startedAt2 = Date.now();
|
|
9869
|
-
const record = (status, extra = {}) =>
|
|
9870
|
-
|
|
9871
|
-
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
|
|
9876
|
-
|
|
9877
|
-
|
|
9878
|
-
|
|
10672
|
+
const record = (status, extra = {}) => {
|
|
10673
|
+
void recordSubagentEvent({
|
|
10674
|
+
kind: "subagent",
|
|
10675
|
+
ts: Date.now(),
|
|
10676
|
+
sessionId: ctx.sessionId ?? "unknown",
|
|
10677
|
+
status,
|
|
10678
|
+
durationMs: Date.now() - startedAt2,
|
|
10679
|
+
costUsd: extra.costUsd ?? 0,
|
|
10680
|
+
...failureReason(extra.error) ? { reason: failureReason(extra.error) } : {},
|
|
10681
|
+
...extra.localChanges ? { localChanges: extra.localChanges } : {}
|
|
10682
|
+
});
|
|
10683
|
+
ctx.trace?.emit(
|
|
10684
|
+
"subagent",
|
|
10685
|
+
{
|
|
10686
|
+
worker_id: handle.id,
|
|
10687
|
+
mode: "hotcell",
|
|
10688
|
+
status,
|
|
10689
|
+
...extra.costUsd !== void 0 ? { cost_usd: extra.costUsd } : {},
|
|
10690
|
+
duration_ms: Date.now() - startedAt2
|
|
10691
|
+
},
|
|
10692
|
+
ctx.turnId ?? null
|
|
10693
|
+
);
|
|
10694
|
+
};
|
|
9879
10695
|
let result2;
|
|
9880
10696
|
try {
|
|
9881
10697
|
result2 = await runHotcellWorker({
|
|
@@ -10547,13 +11363,13 @@ var init_expand_artifact = __esm({
|
|
|
10547
11363
|
// src/jobs/manager.ts
|
|
10548
11364
|
import Database from "better-sqlite3";
|
|
10549
11365
|
import { spawn as spawn3, execFileSync } from "child_process";
|
|
10550
|
-
import { mkdirSync as
|
|
10551
|
-
import { homedir as
|
|
10552
|
-
import { dirname as dirname11, join as
|
|
10553
|
-
import { randomUUID as
|
|
11366
|
+
import { mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync4, readSync, existsSync as existsSync4, statSync as statSync3, closeSync, rmSync } from "fs";
|
|
11367
|
+
import { homedir as homedir13 } from "os";
|
|
11368
|
+
import { dirname as dirname11, join as join23 } from "path";
|
|
11369
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
10554
11370
|
function defaultJobDbPath() {
|
|
10555
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
10556
|
-
return process.env.AUTOPILOT_JOBS_DB ||
|
|
11371
|
+
const root = process.env.XDG_STATE_HOME || join23(homedir13(), ".local", "state");
|
|
11372
|
+
return process.env.AUTOPILOT_JOBS_DB || join23(root, "autopilot", "jobs.db");
|
|
10557
11373
|
}
|
|
10558
11374
|
function isProcessGroupAlive(pgid) {
|
|
10559
11375
|
try {
|
|
@@ -10571,7 +11387,7 @@ function waitForProcessStartTime(pid, jobId, exitPath) {
|
|
|
10571
11387
|
let previous = null;
|
|
10572
11388
|
const title = `autopilot-job-${jobId}`;
|
|
10573
11389
|
while (Date.now() < deadline) {
|
|
10574
|
-
if (
|
|
11390
|
+
if (existsSync4(exitPath)) break;
|
|
10575
11391
|
const current = readProcessStartTime(pid);
|
|
10576
11392
|
const hasUniqueTitle = process.platform !== "darwin" || current?.includes(title) === true;
|
|
10577
11393
|
if (current && current === previous && hasUniqueTitle && !isZombie(pid)) return current;
|
|
@@ -10583,8 +11399,8 @@ function waitForProcessStartTime(pid, jobId, exitPath) {
|
|
|
10583
11399
|
function readProcessStartTime(pid) {
|
|
10584
11400
|
if (process.platform === "linux") {
|
|
10585
11401
|
try {
|
|
10586
|
-
const
|
|
10587
|
-
const fieldsAfterCommand =
|
|
11402
|
+
const stat11 = readFileSync4(`/proc/${pid}/stat`, "utf8");
|
|
11403
|
+
const fieldsAfterCommand = stat11.slice(stat11.lastIndexOf(")") + 1).trim().split(/\s+/);
|
|
10588
11404
|
return fieldsAfterCommand[19] ? `linux:${fieldsAfterCommand[19]}` : null;
|
|
10589
11405
|
} catch {
|
|
10590
11406
|
return null;
|
|
@@ -10696,9 +11512,9 @@ child.on('close', (code, signal) => {
|
|
|
10696
11512
|
db;
|
|
10697
11513
|
jobsDir;
|
|
10698
11514
|
constructor(dbPath = defaultJobDbPath()) {
|
|
10699
|
-
|
|
10700
|
-
this.jobsDir =
|
|
10701
|
-
|
|
11515
|
+
mkdirSync5(dirname11(dbPath), { recursive: true, mode: 448 });
|
|
11516
|
+
this.jobsDir = join23(dirname11(dbPath), "jobs");
|
|
11517
|
+
mkdirSync5(this.jobsDir, { recursive: true, mode: 448 });
|
|
10702
11518
|
this.db = new Database(dbPath);
|
|
10703
11519
|
this.db.pragma("journal_mode = WAL");
|
|
10704
11520
|
this.db.pragma("busy_timeout = 5000");
|
|
@@ -10747,14 +11563,14 @@ child.on('close', (code, signal) => {
|
|
|
10747
11563
|
const existing = this.db.prepare("SELECT * FROM jobs WHERE cwd = ? AND idempotency_key = ?").get(options.cwd, options.idempotencyKey);
|
|
10748
11564
|
if (existing) return toJobRecord(existing);
|
|
10749
11565
|
}
|
|
10750
|
-
const id =
|
|
10751
|
-
const jobDir =
|
|
10752
|
-
|
|
11566
|
+
const id = randomUUID4();
|
|
11567
|
+
const jobDir = join23(this.jobsDir, id);
|
|
11568
|
+
mkdirSync5(jobDir, { recursive: true, mode: 448 });
|
|
10753
11569
|
const paths = {
|
|
10754
|
-
stdoutPath:
|
|
10755
|
-
stderrPath:
|
|
10756
|
-
exitPath:
|
|
10757
|
-
pidPath:
|
|
11570
|
+
stdoutPath: join23(jobDir, "stdout.log"),
|
|
11571
|
+
stderrPath: join23(jobDir, "stderr.log"),
|
|
11572
|
+
exitPath: join23(jobDir, "exit.json"),
|
|
11573
|
+
pidPath: join23(jobDir, "pid")
|
|
10758
11574
|
};
|
|
10759
11575
|
const now2 = Date.now();
|
|
10760
11576
|
try {
|
|
@@ -10807,7 +11623,7 @@ child.on('close', (code, signal) => {
|
|
|
10807
11623
|
const row = this.getRow(id);
|
|
10808
11624
|
if (!row) throw new Error(`Job not found: ${id}`);
|
|
10809
11625
|
const path = stream === "stdout" ? row.stdout_path : row.stderr_path;
|
|
10810
|
-
if (!
|
|
11626
|
+
if (!existsSync4(path)) return { content: "", offset: 0, size: 0, truncated: false };
|
|
10811
11627
|
const size = statSync3(path).size;
|
|
10812
11628
|
if (options.offset !== void 0) {
|
|
10813
11629
|
const offset = Math.max(0, Math.min(size, Math.trunc(options.offset)));
|
|
@@ -10875,9 +11691,9 @@ child.on('close', (code, signal) => {
|
|
|
10875
11691
|
reconcile() {
|
|
10876
11692
|
const rows = this.db.prepare("SELECT * FROM jobs WHERE status IN ('starting', 'running', 'cancelling', 'unknown')").all();
|
|
10877
11693
|
for (const row of rows) {
|
|
10878
|
-
if (
|
|
11694
|
+
if (existsSync4(row.exit_path)) {
|
|
10879
11695
|
try {
|
|
10880
|
-
const result2 = JSON.parse(
|
|
11696
|
+
const result2 = JSON.parse(readFileSync4(row.exit_path, "utf8"));
|
|
10881
11697
|
const status = result2.timedOut ? "timed_out" : row.status === "cancelling" ? "cancelled" : result2.code === 0 ? "completed" : "failed";
|
|
10882
11698
|
this.db.prepare("UPDATE jobs SET status = ?, exit_code = ?, finished_at = COALESCE(finished_at, ?) WHERE id = ?").run(status, result2.code, Date.now(), row.id);
|
|
10883
11699
|
continue;
|
|
@@ -10885,8 +11701,8 @@ child.on('close', (code, signal) => {
|
|
|
10885
11701
|
}
|
|
10886
11702
|
}
|
|
10887
11703
|
let pid = row.pid;
|
|
10888
|
-
if (!pid &&
|
|
10889
|
-
const parsed = Number(
|
|
11704
|
+
if (!pid && existsSync4(row.pid_path)) {
|
|
11705
|
+
const parsed = Number(readFileSync4(row.pid_path, "utf8").trim());
|
|
10890
11706
|
if (Number.isInteger(parsed) && parsed > 0) pid = parsed;
|
|
10891
11707
|
}
|
|
10892
11708
|
if (pid && row.process_start_time) {
|
|
@@ -11032,13 +11848,13 @@ ${result2.content}`;
|
|
|
11032
11848
|
|
|
11033
11849
|
// src/runs/store.ts
|
|
11034
11850
|
import Database2 from "better-sqlite3";
|
|
11035
|
-
import { createHash, randomUUID as
|
|
11036
|
-
import { chmodSync, mkdirSync as
|
|
11037
|
-
import { homedir as
|
|
11038
|
-
import { dirname as dirname12, join as
|
|
11851
|
+
import { createHash as createHash2, randomUUID as randomUUID5 } from "crypto";
|
|
11852
|
+
import { chmodSync, mkdirSync as mkdirSync6 } from "fs";
|
|
11853
|
+
import { homedir as homedir14 } from "os";
|
|
11854
|
+
import { dirname as dirname12, join as join24 } from "path";
|
|
11039
11855
|
function defaultRunsDbPath() {
|
|
11040
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
11041
|
-
return process.env.AUTOPILOT_RUNS_DB ||
|
|
11856
|
+
const root = process.env.XDG_STATE_HOME || join24(homedir14(), ".local", "state");
|
|
11857
|
+
return process.env.AUTOPILOT_RUNS_DB || join24(root, "autopilot", "runs.db");
|
|
11042
11858
|
}
|
|
11043
11859
|
function validateOptionalPositiveInteger(name, value, minimum = 1) {
|
|
11044
11860
|
if (value !== null && (!Number.isSafeInteger(value) || value < minimum)) {
|
|
@@ -11054,7 +11870,7 @@ function stableJson(value) {
|
|
|
11054
11870
|
}
|
|
11055
11871
|
}
|
|
11056
11872
|
function sha256(value) {
|
|
11057
|
-
return
|
|
11873
|
+
return createHash2("sha256").update(value).digest("hex");
|
|
11058
11874
|
}
|
|
11059
11875
|
function rowToRun(row) {
|
|
11060
11876
|
return {
|
|
@@ -11126,7 +11942,7 @@ var init_store = __esm({
|
|
|
11126
11942
|
RunStore = class {
|
|
11127
11943
|
db;
|
|
11128
11944
|
constructor(dbPath = defaultRunsDbPath()) {
|
|
11129
|
-
|
|
11945
|
+
mkdirSync6(dirname12(dbPath), { recursive: true, mode: 448 });
|
|
11130
11946
|
this.db = new Database2(dbPath);
|
|
11131
11947
|
this.db.pragma("journal_mode = WAL");
|
|
11132
11948
|
this.db.pragma("foreign_keys = ON");
|
|
@@ -11231,7 +12047,7 @@ var init_store = __esm({
|
|
|
11231
12047
|
if (maxCostUsd !== null && (!Number.isFinite(maxCostUsd) || maxCostUsd < 0.01)) {
|
|
11232
12048
|
throw new Error("maxCostUsd must be null or a finite number greater than or equal to 0.01");
|
|
11233
12049
|
}
|
|
11234
|
-
const id = input.id ?? input.worktree?.runId ??
|
|
12050
|
+
const id = input.id ?? input.worktree?.runId ?? randomUUID5();
|
|
11235
12051
|
if (!id.trim()) throw new Error("id must not be empty");
|
|
11236
12052
|
if (input.worktree && input.worktree.runId !== id) throw new Error("worktree runId must match run id");
|
|
11237
12053
|
const now2 = Date.now();
|
|
@@ -11425,7 +12241,7 @@ var init_store = __esm({
|
|
|
11425
12241
|
throw new Error("intervalMs must be an integer from 1000 through 604800000");
|
|
11426
12242
|
}
|
|
11427
12243
|
this.assertRunExists(input.runId);
|
|
11428
|
-
const id =
|
|
12244
|
+
const id = randomUUID5();
|
|
11429
12245
|
const now2 = Date.now();
|
|
11430
12246
|
this.db.prepare(`INSERT INTO run_timers
|
|
11431
12247
|
(id, run_id, condition_type, job_id, wake_at, interval_ms, status, max_attempts, created_at)
|
|
@@ -11721,6 +12537,12 @@ function capContentForHook(s) {
|
|
|
11721
12537
|
return `${cut}
|
|
11722
12538
|
[\u2026truncated for hook payload]`;
|
|
11723
12539
|
}
|
|
12540
|
+
function tracePermissionDecision(result2) {
|
|
12541
|
+
if (result2.decision === "deny") return "deny";
|
|
12542
|
+
if (result2.scope === "session") return "allow_session";
|
|
12543
|
+
if (result2.scope === "pattern") return "auto";
|
|
12544
|
+
return "allow";
|
|
12545
|
+
}
|
|
11724
12546
|
function isDiffCommand(cmd) {
|
|
11725
12547
|
const trimmed = cmd.trim();
|
|
11726
12548
|
if (/^git\s+show(?:\s|$)/.test(trimmed)) return true;
|
|
@@ -11741,11 +12563,13 @@ function normalizeToolOutput(result2) {
|
|
|
11741
12563
|
function truncateForError(s) {
|
|
11742
12564
|
return s.length <= 200 ? s : `${s.slice(0, 200)}... [${s.length - 200} more chars]`;
|
|
11743
12565
|
}
|
|
11744
|
-
var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, ToolExecutor;
|
|
12566
|
+
var ALL_TOOLS, RESEARCH_WORKER_TOOL_NAMES, SENSITIVE_RESEARCH_PATHS, HOOK_RESULT_CONTENT_CAP_BYTES, ToolExecutor, TRACE_ARGS_INLINE_MAX, ToolTrace;
|
|
11745
12567
|
var init_executor = __esm({
|
|
11746
12568
|
"src/tools/executor.ts"() {
|
|
11747
12569
|
"use strict";
|
|
11748
12570
|
init_tool_error();
|
|
12571
|
+
init_verification();
|
|
12572
|
+
init_git_delta();
|
|
11749
12573
|
init_read();
|
|
11750
12574
|
init_write();
|
|
11751
12575
|
init_edit();
|
|
@@ -11825,17 +12649,25 @@ var init_executor = __esm({
|
|
|
11825
12649
|
* every `run` call regardless of caller (standard agent loop,
|
|
11826
12650
|
* code-mode sandbox, init turn, SDK, CLI print mode). */
|
|
11827
12651
|
hooks;
|
|
12652
|
+
/** Default session trace recorder; `ctx.trace` (set by the agent loop)
|
|
12653
|
+
* takes precedence per call. */
|
|
12654
|
+
trace;
|
|
11828
12655
|
constructor(tools = ALL_TOOLS, opts2) {
|
|
11829
12656
|
this.tools = new Map(tools.map((t) => [t.name, t]));
|
|
11830
12657
|
this.artifactStore = new ToolArtifactStore();
|
|
11831
12658
|
this.tools.set("expand_artifact", makeExpandArtifactTool(this.artifactStore));
|
|
11832
12659
|
this.hooks = opts2?.hooks ?? null;
|
|
12660
|
+
this.trace = opts2?.trace ?? null;
|
|
11833
12661
|
}
|
|
11834
12662
|
/** Swap or detach the hooks manager. Used by app startup so the
|
|
11835
12663
|
* executor created before the manager exists can pick it up later. */
|
|
11836
12664
|
setHooks(hooks) {
|
|
11837
12665
|
this.hooks = hooks;
|
|
11838
12666
|
}
|
|
12667
|
+
/** Swap or detach the default trace recorder (e.g. when the TUI starts a new session). */
|
|
12668
|
+
setTrace(trace) {
|
|
12669
|
+
this.trace = trace;
|
|
12670
|
+
}
|
|
11839
12671
|
list() {
|
|
11840
12672
|
return [...this.tools.values()];
|
|
11841
12673
|
}
|
|
@@ -11852,8 +12684,17 @@ var init_executor = __esm({
|
|
|
11852
12684
|
this.artifactStore.clear();
|
|
11853
12685
|
}
|
|
11854
12686
|
async run(call, askPermission, ctx, onFileChange) {
|
|
12687
|
+
const trace = ctx.trace ?? this.trace;
|
|
12688
|
+
if (!trace?.enabled) return this.runInner(call, askPermission, ctx, onFileChange, null);
|
|
12689
|
+
const tr = new ToolTrace(trace, ctx, call);
|
|
12690
|
+
const result2 = await this.runInner(call, askPermission, ctx, onFileChange, tr);
|
|
12691
|
+
tr.finish(result2);
|
|
12692
|
+
return result2;
|
|
12693
|
+
}
|
|
12694
|
+
async runInner(call, askPermission, ctx, onFileChange, tr) {
|
|
11855
12695
|
const tool = this.tools.get(call.name) ?? (call.name === "spawn_worker" ? this.tools.get("subagent") : void 0);
|
|
11856
12696
|
if (!tool) {
|
|
12697
|
+
tr?.call(null, false);
|
|
11857
12698
|
return {
|
|
11858
12699
|
tool_call_id: call.id,
|
|
11859
12700
|
name: call.name,
|
|
@@ -11867,6 +12708,7 @@ var init_executor = __esm({
|
|
|
11867
12708
|
try {
|
|
11868
12709
|
args = call.arguments.trim() ? JSON.parse(call.arguments) : {};
|
|
11869
12710
|
} catch (e) {
|
|
12711
|
+
tr?.call(null, tool.needsPermission);
|
|
11870
12712
|
return {
|
|
11871
12713
|
tool_call_id: call.id,
|
|
11872
12714
|
name: call.name,
|
|
@@ -11877,6 +12719,7 @@ var init_executor = __esm({
|
|
|
11877
12719
|
suggestion: "reformulate the tool call with valid JSON arguments"
|
|
11878
12720
|
};
|
|
11879
12721
|
}
|
|
12722
|
+
tr?.call(args, tool.needsPermission);
|
|
11880
12723
|
if (this.hooks?.hasEnabledHooks("PreToolUse")) {
|
|
11881
12724
|
const preOutcome = await this.hooks.fire(
|
|
11882
12725
|
"PreToolUse",
|
|
@@ -11908,8 +12751,10 @@ var init_executor = __esm({
|
|
|
11908
12751
|
if (tool.needsPermission) {
|
|
11909
12752
|
const sessionKey = this.permissionKey(tool, args);
|
|
11910
12753
|
if (!this.sessionAllowed.has(sessionKey)) {
|
|
12754
|
+
const askedAt = performance.now();
|
|
11911
12755
|
const raw = await askPermission({ tool, args, sessionKey });
|
|
11912
12756
|
const result2 = toPermissionResult(raw);
|
|
12757
|
+
tr?.permission(tracePermissionDecision(result2), Math.round(performance.now() - askedAt), result2.feedback);
|
|
11913
12758
|
if (result2.decision === "deny") {
|
|
11914
12759
|
const denied = {
|
|
11915
12760
|
tool_call_id: call.id,
|
|
@@ -11924,7 +12769,11 @@ var init_executor = __esm({
|
|
|
11924
12769
|
return denied;
|
|
11925
12770
|
}
|
|
11926
12771
|
if (result2.scope === "session") this.sessionAllowed.add(sessionKey);
|
|
12772
|
+
} else {
|
|
12773
|
+
tr?.permission("auto", 0);
|
|
11927
12774
|
}
|
|
12775
|
+
} else {
|
|
12776
|
+
tr?.permission("auto", 0);
|
|
11928
12777
|
}
|
|
11929
12778
|
let runStore = null;
|
|
11930
12779
|
let intentRecorded = false;
|
|
@@ -11938,6 +12787,7 @@ var init_executor = __esm({
|
|
|
11938
12787
|
const result2 = await tool.run(args, ctx);
|
|
11939
12788
|
toolCompleted = true;
|
|
11940
12789
|
const normalized = normalizeToolOutput(result2);
|
|
12790
|
+
tr?.raw(normalized);
|
|
11941
12791
|
if (runStore && ctx.runId) {
|
|
11942
12792
|
runStore.recordToolResult(ctx.runId, call.id, call.name, { ok: true, content: normalized.content });
|
|
11943
12793
|
}
|
|
@@ -11991,6 +12841,7 @@ var init_executor = __esm({
|
|
|
11991
12841
|
if (e instanceof RunToolBudgetExceededError) ctx.onRunBudgetExceeded?.(e.reason);
|
|
11992
12842
|
const err = wrapAsToolError(e);
|
|
11993
12843
|
const msg = `Error running ${call.name}: ${err.message}`;
|
|
12844
|
+
tr?.raw({ content: msg, rawBytes: Buffer.byteLength(msg, "utf8"), reducedBytes: Buffer.byteLength(msg, "utf8") });
|
|
11994
12845
|
const failure = {
|
|
11995
12846
|
tool_call_id: call.id,
|
|
11996
12847
|
name: call.name,
|
|
@@ -12051,6 +12902,121 @@ var init_executor = __esm({
|
|
|
12051
12902
|
return tool.name;
|
|
12052
12903
|
}
|
|
12053
12904
|
};
|
|
12905
|
+
TRACE_ARGS_INLINE_MAX = 2 * 1024;
|
|
12906
|
+
ToolTrace = class {
|
|
12907
|
+
constructor(trace, ctx, invocation) {
|
|
12908
|
+
this.trace = trace;
|
|
12909
|
+
this.invocation = invocation;
|
|
12910
|
+
this.turnId = ctx.turnId ?? null;
|
|
12911
|
+
this.parentId = ctx.codeModeParentToolCallId;
|
|
12912
|
+
this.sessionId = ctx.sessionId;
|
|
12913
|
+
}
|
|
12914
|
+
trace;
|
|
12915
|
+
invocation;
|
|
12916
|
+
startedAt = performance.now();
|
|
12917
|
+
turnId;
|
|
12918
|
+
parentId;
|
|
12919
|
+
sessionId;
|
|
12920
|
+
rawOutput = null;
|
|
12921
|
+
argsBlob = "";
|
|
12922
|
+
args = null;
|
|
12923
|
+
/** The call was parsed (args null when the arguments were not valid JSON). */
|
|
12924
|
+
call(args, needsPermission) {
|
|
12925
|
+
this.args = args;
|
|
12926
|
+
this.argsBlob = this.trace.blob(this.invocation.arguments) ?? "";
|
|
12927
|
+
if (this.parentId) return;
|
|
12928
|
+
const payload = {
|
|
12929
|
+
tool_call_id: this.invocation.id,
|
|
12930
|
+
name: this.invocation.name,
|
|
12931
|
+
args_blob: this.argsBlob,
|
|
12932
|
+
...args && this.invocation.arguments.length <= TRACE_ARGS_INLINE_MAX ? { args_inline: args } : {},
|
|
12933
|
+
needs_permission: needsPermission,
|
|
12934
|
+
code_mode_redirected: false
|
|
12935
|
+
};
|
|
12936
|
+
this.trace.emit("tool_call", payload, this.turnId);
|
|
12937
|
+
}
|
|
12938
|
+
permission(decision, latencyMs, feedback) {
|
|
12939
|
+
this.trace.emit(
|
|
12940
|
+
"permission_decision",
|
|
12941
|
+
{
|
|
12942
|
+
tool_call_id: this.invocation.id,
|
|
12943
|
+
decision,
|
|
12944
|
+
...feedback ? { feedback_text: feedback } : {},
|
|
12945
|
+
latency_ms: latencyMs
|
|
12946
|
+
},
|
|
12947
|
+
this.turnId
|
|
12948
|
+
);
|
|
12949
|
+
}
|
|
12950
|
+
/** The tool's output before reduction. */
|
|
12951
|
+
raw(output) {
|
|
12952
|
+
this.rawOutput = output;
|
|
12953
|
+
}
|
|
12954
|
+
finish(result2) {
|
|
12955
|
+
const durationMs = Math.round(performance.now() - this.startedAt);
|
|
12956
|
+
const rawContent = this.rawOutput?.content ?? result2.content;
|
|
12957
|
+
const rawBlob = this.trace.blob(rawContent) ?? "";
|
|
12958
|
+
this.outcomes(result2);
|
|
12959
|
+
if (this.parentId) {
|
|
12960
|
+
this.trace.emit(
|
|
12961
|
+
"code_mode_call",
|
|
12962
|
+
{
|
|
12963
|
+
parent_tool_call_id: this.parentId,
|
|
12964
|
+
name: this.invocation.name,
|
|
12965
|
+
args_blob: this.argsBlob,
|
|
12966
|
+
raw_blob: rawBlob,
|
|
12967
|
+
ok: result2.ok,
|
|
12968
|
+
duration_ms: durationMs
|
|
12969
|
+
},
|
|
12970
|
+
this.turnId
|
|
12971
|
+
);
|
|
12972
|
+
return;
|
|
12973
|
+
}
|
|
12974
|
+
const meta = this.rawOutput?.meta;
|
|
12975
|
+
const payload = {
|
|
12976
|
+
tool_call_id: this.invocation.id,
|
|
12977
|
+
name: this.invocation.name,
|
|
12978
|
+
ok: result2.ok,
|
|
12979
|
+
...result2.errorCode ? { error_code: result2.errorCode } : {},
|
|
12980
|
+
raw_blob: rawBlob,
|
|
12981
|
+
raw_bytes: Buffer.byteLength(rawContent, "utf8"),
|
|
12982
|
+
reduced_blob: rawContent === result2.content ? rawBlob : this.trace.blob(result2.content) ?? "",
|
|
12983
|
+
reduced_bytes: Buffer.byteLength(result2.content, "utf8"),
|
|
12984
|
+
...result2.artifactId ? { artifact_id: result2.artifactId } : {},
|
|
12985
|
+
...meta && meta.exitCode !== void 0 && meta.exitCode !== null ? { exit_code: meta.exitCode } : {},
|
|
12986
|
+
...meta?.timedOut !== void 0 ? { timed_out: meta.timedOut } : {},
|
|
12987
|
+
duration_ms: durationMs
|
|
12988
|
+
};
|
|
12989
|
+
this.trace.emit("tool_result", payload, this.turnId);
|
|
12990
|
+
}
|
|
12991
|
+
/** Outcome signals a bash call carries: a verification exit code, or a git revert of the last delta. */
|
|
12992
|
+
outcomes(result2) {
|
|
12993
|
+
if (this.invocation.name !== "bash") return;
|
|
12994
|
+
const command = this.args?.command;
|
|
12995
|
+
if (typeof command !== "string" || !command.trim()) return;
|
|
12996
|
+
const exitCode = this.rawOutput?.meta?.exitCode;
|
|
12997
|
+
const category = classifyVerification(command);
|
|
12998
|
+
if (category && typeof exitCode === "number") {
|
|
12999
|
+
this.trace.emit(
|
|
13000
|
+
"outcome",
|
|
13001
|
+
{
|
|
13002
|
+
kind: "verification",
|
|
13003
|
+
turn_id: this.turnId ?? "",
|
|
13004
|
+
tool_call_id: this.invocation.id,
|
|
13005
|
+
command,
|
|
13006
|
+
category,
|
|
13007
|
+
exit_code: exitCode
|
|
13008
|
+
},
|
|
13009
|
+
this.turnId
|
|
13010
|
+
);
|
|
13011
|
+
}
|
|
13012
|
+
if (result2.ok && this.sessionId) {
|
|
13013
|
+
const reverted = detectGitRevert(this.sessionId, command);
|
|
13014
|
+
if (reverted) {
|
|
13015
|
+
this.trace.emit("outcome", { kind: "reverted", turn_id: reverted.turnId, how: "git_checkout" }, this.turnId);
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
13018
|
+
}
|
|
13019
|
+
};
|
|
12054
13020
|
}
|
|
12055
13021
|
});
|
|
12056
13022
|
|
|
@@ -12068,11 +13034,11 @@ __export(sessions_exports, {
|
|
|
12068
13034
|
sessionsDir: () => sessionsDir
|
|
12069
13035
|
});
|
|
12070
13036
|
import { readFile as readFile13, writeFile as writeFile11, mkdir as mkdir11, readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
12071
|
-
import { homedir as
|
|
12072
|
-
import { join as
|
|
13037
|
+
import { homedir as homedir15 } from "os";
|
|
13038
|
+
import { join as join25 } from "path";
|
|
12073
13039
|
function sessionsDir() {
|
|
12074
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
12075
|
-
return
|
|
13040
|
+
const xdg = process.env.XDG_DATA_HOME || join25(homedir15(), ".local", "share");
|
|
13041
|
+
return join25(xdg, "kimiflare", "sessions");
|
|
12076
13042
|
}
|
|
12077
13043
|
function sanitize(text) {
|
|
12078
13044
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
@@ -12092,7 +13058,7 @@ function makeSessionId(firstPrompt) {
|
|
|
12092
13058
|
async function saveSession(file) {
|
|
12093
13059
|
const dir = sessionsDir();
|
|
12094
13060
|
await mkdir11(dir, { recursive: true });
|
|
12095
|
-
const path =
|
|
13061
|
+
const path = join25(dir, `${file.id}.json`);
|
|
12096
13062
|
await writeFile11(path, JSON.stringify(file, null, 2), "utf8");
|
|
12097
13063
|
return path;
|
|
12098
13064
|
}
|
|
@@ -12112,7 +13078,7 @@ async function listSessions(limit = 30, cwd) {
|
|
|
12112
13078
|
const summaries = [];
|
|
12113
13079
|
for (const name of entries) {
|
|
12114
13080
|
if (!name.endsWith(".json")) continue;
|
|
12115
|
-
const path =
|
|
13081
|
+
const path = join25(dir, name);
|
|
12116
13082
|
try {
|
|
12117
13083
|
const [s, raw] = await Promise.all([stat5(path), readFile13(path, "utf8")]);
|
|
12118
13084
|
const parsed = JSON.parse(raw);
|
|
@@ -12137,7 +13103,9 @@ async function listSessions(limit = 30, cwd) {
|
|
|
12137
13103
|
}
|
|
12138
13104
|
async function loadSession(filePath) {
|
|
12139
13105
|
const raw = await readFile13(filePath, "utf8");
|
|
12140
|
-
|
|
13106
|
+
const file = JSON.parse(raw);
|
|
13107
|
+
if (Array.isArray(file.messages)) repairDanglingToolCalls(file.messages);
|
|
13108
|
+
return file;
|
|
12141
13109
|
}
|
|
12142
13110
|
async function addCheckpoint(filePath, checkpoint) {
|
|
12143
13111
|
const file = await loadSession(filePath);
|
|
@@ -12166,6 +13134,7 @@ var INTENT_PREFIX_MAP;
|
|
|
12166
13134
|
var init_sessions = __esm({
|
|
12167
13135
|
"src/sessions.ts"() {
|
|
12168
13136
|
"use strict";
|
|
13137
|
+
init_messages();
|
|
12169
13138
|
init_storage_limits();
|
|
12170
13139
|
INTENT_PREFIX_MAP = {
|
|
12171
13140
|
diagnose: "Bug:",
|
|
@@ -12223,7 +13192,7 @@ var init_image = __esm({
|
|
|
12223
13192
|
|
|
12224
13193
|
// src/permissions-evaluator.ts
|
|
12225
13194
|
import { resolve as resolve5, relative as relative4 } from "path";
|
|
12226
|
-
import { homedir as
|
|
13195
|
+
import { homedir as homedir16 } from "os";
|
|
12227
13196
|
function evaluatePermissionRules(req, rules) {
|
|
12228
13197
|
const toolRules = rules[req.tool];
|
|
12229
13198
|
if (!toolRules) return "ask";
|
|
@@ -12239,7 +13208,7 @@ function evaluatePermissionRules(req, rules) {
|
|
|
12239
13208
|
}
|
|
12240
13209
|
function expandHome(path) {
|
|
12241
13210
|
if (path.startsWith("~/")) {
|
|
12242
|
-
return resolve5(
|
|
13211
|
+
return resolve5(homedir16(), path.slice(2));
|
|
12243
13212
|
}
|
|
12244
13213
|
return path;
|
|
12245
13214
|
}
|
|
@@ -12265,7 +13234,7 @@ function extractTarget(tool, args, cwd) {
|
|
|
12265
13234
|
function matchPattern(target, pattern, cwd) {
|
|
12266
13235
|
let expandedPattern = pattern;
|
|
12267
13236
|
if (pattern.startsWith("~/")) {
|
|
12268
|
-
expandedPattern = resolve5(
|
|
13237
|
+
expandedPattern = resolve5(homedir16(), pattern.slice(2));
|
|
12269
13238
|
}
|
|
12270
13239
|
if (target.startsWith(expandedPattern)) {
|
|
12271
13240
|
return true;
|
|
@@ -12342,9 +13311,237 @@ var init_classify = __esm({
|
|
|
12342
13311
|
}
|
|
12343
13312
|
});
|
|
12344
13313
|
|
|
13314
|
+
// src/trace/retention.ts
|
|
13315
|
+
var retention_exports = {};
|
|
13316
|
+
__export(retention_exports, {
|
|
13317
|
+
listTraceSessions: () => listTraceSessions,
|
|
13318
|
+
pruneTraces: () => pruneTraces
|
|
13319
|
+
});
|
|
13320
|
+
import { readdir as readdir5, rm as rm3, stat as stat6 } from "fs/promises";
|
|
13321
|
+
import { join as join26 } from "path";
|
|
13322
|
+
async function dirSize(path) {
|
|
13323
|
+
let total = 0;
|
|
13324
|
+
const entries = await readdir5(path, { withFileTypes: true });
|
|
13325
|
+
for (const entry of entries) {
|
|
13326
|
+
const p = join26(path, entry.name);
|
|
13327
|
+
if (entry.isDirectory()) total += await dirSize(p);
|
|
13328
|
+
else if (entry.isFile()) {
|
|
13329
|
+
try {
|
|
13330
|
+
total += (await stat6(p)).size;
|
|
13331
|
+
} catch {
|
|
13332
|
+
}
|
|
13333
|
+
}
|
|
13334
|
+
}
|
|
13335
|
+
return total;
|
|
13336
|
+
}
|
|
13337
|
+
async function listTraceSessions(root) {
|
|
13338
|
+
const base = traceRoot(root);
|
|
13339
|
+
let names;
|
|
13340
|
+
try {
|
|
13341
|
+
names = await readdir5(base);
|
|
13342
|
+
} catch {
|
|
13343
|
+
return [];
|
|
13344
|
+
}
|
|
13345
|
+
const sessions = [];
|
|
13346
|
+
for (const name of names) {
|
|
13347
|
+
const path = join26(base, name);
|
|
13348
|
+
try {
|
|
13349
|
+
const s = await stat6(path);
|
|
13350
|
+
if (!s.isDirectory()) continue;
|
|
13351
|
+
let mtime = s.mtime;
|
|
13352
|
+
try {
|
|
13353
|
+
mtime = (await stat6(join26(path, TRACE_FILE_NAME))).mtime;
|
|
13354
|
+
} catch {
|
|
13355
|
+
}
|
|
13356
|
+
sessions.push({ sessionId: name, path, mtime, bytes: await dirSize(path) });
|
|
13357
|
+
} catch {
|
|
13358
|
+
}
|
|
13359
|
+
}
|
|
13360
|
+
sessions.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
13361
|
+
return sessions;
|
|
13362
|
+
}
|
|
13363
|
+
async function pruneTraces(opts2 = {}) {
|
|
13364
|
+
const maxAgeDays = opts2.maxAgeDays ?? RETENTION.traceMaxAgeDays;
|
|
13365
|
+
const maxTotalBytes = opts2.maxTotalBytes ?? RETENTION.traceMaxTotalBytes;
|
|
13366
|
+
const maxSessionBytes = opts2.maxSessionBytes ?? RETENTION.traceMaxSessionBytes;
|
|
13367
|
+
const now2 = opts2.now ?? Date.now();
|
|
13368
|
+
const cutoff = now2 - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
13369
|
+
const removed = [];
|
|
13370
|
+
let sessions;
|
|
13371
|
+
try {
|
|
13372
|
+
sessions = await listTraceSessions(opts2.root);
|
|
13373
|
+
} catch {
|
|
13374
|
+
return { removed, keptBytes: 0 };
|
|
13375
|
+
}
|
|
13376
|
+
const remove = async (s) => {
|
|
13377
|
+
try {
|
|
13378
|
+
await rm3(s.path, { recursive: true, force: true });
|
|
13379
|
+
removed.push(s.sessionId);
|
|
13380
|
+
} catch {
|
|
13381
|
+
}
|
|
13382
|
+
};
|
|
13383
|
+
const kept = [];
|
|
13384
|
+
for (const s of sessions) {
|
|
13385
|
+
if (s.mtime.getTime() < cutoff || s.bytes > maxSessionBytes) await remove(s);
|
|
13386
|
+
else kept.push(s);
|
|
13387
|
+
}
|
|
13388
|
+
let total = kept.reduce((sum, s) => sum + s.bytes, 0);
|
|
13389
|
+
while (total > maxTotalBytes && kept.length > 0) {
|
|
13390
|
+
const oldest = kept.pop();
|
|
13391
|
+
await remove(oldest);
|
|
13392
|
+
total -= oldest.bytes;
|
|
13393
|
+
}
|
|
13394
|
+
return { removed, keptBytes: total };
|
|
13395
|
+
}
|
|
13396
|
+
var init_retention = __esm({
|
|
13397
|
+
"src/trace/retention.ts"() {
|
|
13398
|
+
"use strict";
|
|
13399
|
+
init_storage_limits();
|
|
13400
|
+
init_paths();
|
|
13401
|
+
}
|
|
13402
|
+
});
|
|
13403
|
+
|
|
13404
|
+
// src/trace/session-start.ts
|
|
13405
|
+
import { execFile as execFile5 } from "child_process";
|
|
13406
|
+
import { existsSync as existsSync5 } from "fs";
|
|
13407
|
+
import { dirname as dirname13, join as join27 } from "path";
|
|
13408
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
13409
|
+
import { promisify as promisify5 } from "util";
|
|
13410
|
+
async function git2(args, cwd) {
|
|
13411
|
+
try {
|
|
13412
|
+
const { stdout } = await execFileAsync4("git", args, { cwd, timeout: 3e3, windowsHide: true });
|
|
13413
|
+
const out = stdout.trim();
|
|
13414
|
+
return out || null;
|
|
13415
|
+
} catch {
|
|
13416
|
+
return null;
|
|
13417
|
+
}
|
|
13418
|
+
}
|
|
13419
|
+
function harnessCheckoutDir() {
|
|
13420
|
+
const here = dirname13(fileURLToPath4(import.meta.url));
|
|
13421
|
+
for (const candidate of [join27(here, "..", ".."), join27(here, "..")]) {
|
|
13422
|
+
if (existsSync5(join27(candidate, "package.json")) && existsSync5(join27(candidate, ".git"))) return candidate;
|
|
13423
|
+
}
|
|
13424
|
+
return null;
|
|
13425
|
+
}
|
|
13426
|
+
async function resolveHarnessCommit() {
|
|
13427
|
+
const dir = harnessCheckoutDir();
|
|
13428
|
+
if (!dir) return null;
|
|
13429
|
+
return git2(["rev-parse", "HEAD"], dir);
|
|
13430
|
+
}
|
|
13431
|
+
async function collectSessionStart(opts2, blob) {
|
|
13432
|
+
const toolsJson = JSON.stringify(opts2.tools);
|
|
13433
|
+
const [harnessCommit, repoRemote, repoHead] = await Promise.all([
|
|
13434
|
+
resolveHarnessCommit(),
|
|
13435
|
+
git2(["remote", "get-url", "origin"], opts2.cwd),
|
|
13436
|
+
git2(["rev-parse", "HEAD"], opts2.cwd)
|
|
13437
|
+
]);
|
|
13438
|
+
return {
|
|
13439
|
+
autopilot_version: getAppVersion(),
|
|
13440
|
+
harness_commit: harnessCommit,
|
|
13441
|
+
cwd: opts2.cwd,
|
|
13442
|
+
repo_remote: repoRemote,
|
|
13443
|
+
repo_head: repoHead,
|
|
13444
|
+
model: opts2.model,
|
|
13445
|
+
mode: opts2.mode,
|
|
13446
|
+
config: redactConfig(opts2.config ?? {}),
|
|
13447
|
+
tool_profile: opts2.toolProfile ?? "full",
|
|
13448
|
+
tool_schemas_sha: sha256Hex(toolsJson),
|
|
13449
|
+
tools_blob: blob(toolsJson) ?? "",
|
|
13450
|
+
system_prompt_sha: sha256Hex(opts2.systemPrompt)
|
|
13451
|
+
};
|
|
13452
|
+
}
|
|
13453
|
+
async function emitSessionStart(recorder, opts2) {
|
|
13454
|
+
if (!recorder.enabled) return;
|
|
13455
|
+
const payload = await collectSessionStart(opts2, (content) => recorder.blob(content));
|
|
13456
|
+
recorder.emit("session_start", payload, null);
|
|
13457
|
+
}
|
|
13458
|
+
var execFileAsync4;
|
|
13459
|
+
var init_session_start = __esm({
|
|
13460
|
+
"src/trace/session-start.ts"() {
|
|
13461
|
+
"use strict";
|
|
13462
|
+
init_version();
|
|
13463
|
+
init_blobs();
|
|
13464
|
+
init_redact();
|
|
13465
|
+
execFileAsync4 = promisify5(execFile5);
|
|
13466
|
+
}
|
|
13467
|
+
});
|
|
13468
|
+
|
|
13469
|
+
// src/trace/compaction.ts
|
|
13470
|
+
function traceCompiledCompaction(trace, result2, turnId = null) {
|
|
13471
|
+
if (!trace?.enabled || result2.metrics.rawTurnsRemoved === 0) return;
|
|
13472
|
+
trace.emit(
|
|
13473
|
+
"compaction",
|
|
13474
|
+
{
|
|
13475
|
+
method: "compiled",
|
|
13476
|
+
tokens_before: result2.metrics.estimatedTokensBefore,
|
|
13477
|
+
tokens_after: result2.metrics.estimatedTokensAfter,
|
|
13478
|
+
turns_removed: result2.metrics.rawTurnsRemoved,
|
|
13479
|
+
artifacts_archived: result2.metrics.archivedArtifacts
|
|
13480
|
+
},
|
|
13481
|
+
turnId
|
|
13482
|
+
);
|
|
13483
|
+
}
|
|
13484
|
+
function traceLlmCompaction(trace, before, result2, turnId = null) {
|
|
13485
|
+
if (!trace?.enabled || result2.replacedCount === 0) return;
|
|
13486
|
+
trace.emit(
|
|
13487
|
+
"compaction",
|
|
13488
|
+
{
|
|
13489
|
+
method: "llm",
|
|
13490
|
+
tokens_before: estimatePromptTokens(before),
|
|
13491
|
+
tokens_after: estimatePromptTokens(result2.newMessages),
|
|
13492
|
+
turns_removed: result2.replacedCount,
|
|
13493
|
+
...result2.summary ? { summary_blob: trace.blob(result2.summary) ?? "" } : {}
|
|
13494
|
+
},
|
|
13495
|
+
turnId
|
|
13496
|
+
);
|
|
13497
|
+
}
|
|
13498
|
+
var init_compaction = __esm({
|
|
13499
|
+
"src/trace/compaction.ts"() {
|
|
13500
|
+
"use strict";
|
|
13501
|
+
init_artifact_compaction();
|
|
13502
|
+
}
|
|
13503
|
+
});
|
|
13504
|
+
|
|
13505
|
+
// src/trace/next-message.ts
|
|
13506
|
+
function classifyNextMessage(text) {
|
|
13507
|
+
const trimmed = text.trim();
|
|
13508
|
+
if (!trimmed) return "other";
|
|
13509
|
+
if (trimmed.startsWith("/")) return "other";
|
|
13510
|
+
if (CORRECTION.test(trimmed)) return "correction";
|
|
13511
|
+
if (CONTINUE.test(trimmed)) return "continue";
|
|
13512
|
+
if (trimmed.endsWith("?")) return "question";
|
|
13513
|
+
return "new_task";
|
|
13514
|
+
}
|
|
13515
|
+
var CORRECTION, CONTINUE;
|
|
13516
|
+
var init_next_message = __esm({
|
|
13517
|
+
"src/trace/next-message.ts"() {
|
|
13518
|
+
"use strict";
|
|
13519
|
+
CORRECTION = /^(no\b|nope\b|wrong\b|that's not\b|that is not\b|thats not\b|not what\b|undo\b|revert\b|stop\b|don't\b|dont\b)/i;
|
|
13520
|
+
CONTINUE = /^(go on\b|continue\b|yes\b|yep\b|yeah\b|ok\b|okay\b|do it\b|proceed\b|sure\b|sounds good\b|lgtm\b|looks good\b|next\b)/i;
|
|
13521
|
+
}
|
|
13522
|
+
});
|
|
13523
|
+
|
|
13524
|
+
// src/trace/index.ts
|
|
13525
|
+
var init_trace = __esm({
|
|
13526
|
+
"src/trace/index.ts"() {
|
|
13527
|
+
"use strict";
|
|
13528
|
+
init_types();
|
|
13529
|
+
init_recorder();
|
|
13530
|
+
init_blobs();
|
|
13531
|
+
init_redact();
|
|
13532
|
+
init_paths();
|
|
13533
|
+
init_retention();
|
|
13534
|
+
init_session_start();
|
|
13535
|
+
init_compaction();
|
|
13536
|
+
init_verification();
|
|
13537
|
+
init_next_message();
|
|
13538
|
+
init_git_delta();
|
|
13539
|
+
}
|
|
13540
|
+
});
|
|
13541
|
+
|
|
12345
13542
|
// src/hooks/types.ts
|
|
12346
13543
|
var HOOK_EVENTS;
|
|
12347
|
-
var
|
|
13544
|
+
var init_types2 = __esm({
|
|
12348
13545
|
"src/hooks/types.ts"() {
|
|
12349
13546
|
"use strict";
|
|
12350
13547
|
HOOK_EVENTS = [
|
|
@@ -12358,21 +13555,21 @@ var init_types = __esm({
|
|
|
12358
13555
|
});
|
|
12359
13556
|
|
|
12360
13557
|
// src/hooks/settings.ts
|
|
12361
|
-
import { existsSync as
|
|
12362
|
-
import { homedir as
|
|
12363
|
-
import { join as
|
|
12364
|
-
import { createHash as
|
|
13558
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
13559
|
+
import { homedir as homedir17 } from "os";
|
|
13560
|
+
import { join as join28, dirname as dirname14 } from "path";
|
|
13561
|
+
import { createHash as createHash3 } from "crypto";
|
|
12365
13562
|
function globalSettingsPath() {
|
|
12366
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
12367
|
-
return
|
|
13563
|
+
const xdg = process.env.XDG_CONFIG_HOME || join28(homedir17(), ".config");
|
|
13564
|
+
return join28(xdg, "kimiflare", "settings.json");
|
|
12368
13565
|
}
|
|
12369
13566
|
function projectSettingsPath(cwd) {
|
|
12370
|
-
return
|
|
13567
|
+
return join28(cwd, ".kimiflare", "settings.json");
|
|
12371
13568
|
}
|
|
12372
13569
|
function readSettingsFile(path) {
|
|
12373
|
-
if (!
|
|
13570
|
+
if (!existsSync6(path)) return null;
|
|
12374
13571
|
try {
|
|
12375
|
-
const raw =
|
|
13572
|
+
const raw = readFileSync5(path, "utf8");
|
|
12376
13573
|
const parsed = JSON.parse(raw);
|
|
12377
13574
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
12378
13575
|
} catch {
|
|
@@ -12380,7 +13577,7 @@ function readSettingsFile(path) {
|
|
|
12380
13577
|
}
|
|
12381
13578
|
}
|
|
12382
13579
|
function deriveHookId(event, command) {
|
|
12383
|
-
const h =
|
|
13580
|
+
const h = createHash3("sha256").update(`${event}\0${command}`).digest("hex");
|
|
12384
13581
|
return h.slice(0, 8);
|
|
12385
13582
|
}
|
|
12386
13583
|
function normalizeHook(event, raw, source) {
|
|
@@ -12443,8 +13640,8 @@ function appendHook(scope, cwd, event, hook) {
|
|
|
12443
13640
|
return rest;
|
|
12444
13641
|
});
|
|
12445
13642
|
existing.hooks = hooks;
|
|
12446
|
-
|
|
12447
|
-
|
|
13643
|
+
mkdirSync7(dirname14(path), { recursive: true });
|
|
13644
|
+
writeFileSync4(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
12448
13645
|
return path;
|
|
12449
13646
|
}
|
|
12450
13647
|
function setHookEnabled(cwd, id, enabled2) {
|
|
@@ -12469,8 +13666,8 @@ function setHookEnabled(cwd, id, enabled2) {
|
|
|
12469
13666
|
}
|
|
12470
13667
|
}
|
|
12471
13668
|
if (changed) {
|
|
12472
|
-
|
|
12473
|
-
|
|
13669
|
+
mkdirSync7(dirname14(path), { recursive: true });
|
|
13670
|
+
writeFileSync4(path, JSON.stringify(existing, null, 2) + "\n", "utf8");
|
|
12474
13671
|
return path;
|
|
12475
13672
|
}
|
|
12476
13673
|
void scope;
|
|
@@ -12480,7 +13677,7 @@ function setHookEnabled(cwd, id, enabled2) {
|
|
|
12480
13677
|
var init_settings = __esm({
|
|
12481
13678
|
"src/hooks/settings.ts"() {
|
|
12482
13679
|
"use strict";
|
|
12483
|
-
|
|
13680
|
+
init_types2();
|
|
12484
13681
|
}
|
|
12485
13682
|
});
|
|
12486
13683
|
|
|
@@ -12698,11 +13895,11 @@ __export(cost_verify_exports, {
|
|
|
12698
13895
|
verifyTurn: () => verifyTurn
|
|
12699
13896
|
});
|
|
12700
13897
|
import { readFile as readFile16 } from "fs/promises";
|
|
12701
|
-
import { homedir as
|
|
12702
|
-
import { join as
|
|
13898
|
+
import { homedir as homedir18 } from "os";
|
|
13899
|
+
import { join as join29 } from "path";
|
|
12703
13900
|
function usagePath2() {
|
|
12704
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
12705
|
-
return
|
|
13901
|
+
const xdg = process.env.XDG_DATA_HOME || join29(homedir18(), ".local", "share");
|
|
13902
|
+
return join29(xdg, "kimiflare", "usage.json");
|
|
12706
13903
|
}
|
|
12707
13904
|
async function loadSessions() {
|
|
12708
13905
|
try {
|
|
@@ -12795,7 +13992,7 @@ var init_cost_verify = __esm({
|
|
|
12795
13992
|
|
|
12796
13993
|
// src/cost-attribution/types.ts
|
|
12797
13994
|
var ALL_CATEGORIES;
|
|
12798
|
-
var
|
|
13995
|
+
var init_types3 = __esm({
|
|
12799
13996
|
"src/cost-attribution/types.ts"() {
|
|
12800
13997
|
"use strict";
|
|
12801
13998
|
ALL_CATEGORIES = [
|
|
@@ -12874,7 +14071,7 @@ function buildReport(opts2) {
|
|
|
12874
14071
|
var init_report = __esm({
|
|
12875
14072
|
"src/cost-attribution/report.ts"() {
|
|
12876
14073
|
"use strict";
|
|
12877
|
-
|
|
14074
|
+
init_types3();
|
|
12878
14075
|
}
|
|
12879
14076
|
});
|
|
12880
14077
|
|
|
@@ -13238,11 +14435,11 @@ var init_heuristic = __esm({
|
|
|
13238
14435
|
|
|
13239
14436
|
// src/cost-attribution/classify-from-session.ts
|
|
13240
14437
|
import { readFile as readFile17 } from "fs/promises";
|
|
13241
|
-
import { join as
|
|
13242
|
-
import { homedir as
|
|
14438
|
+
import { join as join30 } from "path";
|
|
14439
|
+
import { homedir as homedir19 } from "os";
|
|
13243
14440
|
function sessionsDir2() {
|
|
13244
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
13245
|
-
return
|
|
14441
|
+
const xdg = process.env.XDG_DATA_HOME || join30(homedir19(), ".local", "share");
|
|
14442
|
+
return join30(xdg, "kimiflare", "sessions");
|
|
13246
14443
|
}
|
|
13247
14444
|
function parseToolCalls(calls) {
|
|
13248
14445
|
return calls.map((c) => {
|
|
@@ -13256,7 +14453,7 @@ function parseToolCalls(calls) {
|
|
|
13256
14453
|
}
|
|
13257
14454
|
async function classifyFromSessionFile(sessionId) {
|
|
13258
14455
|
try {
|
|
13259
|
-
const raw = await readFile17(
|
|
14456
|
+
const raw = await readFile17(join30(sessionsDir2(), `${sessionId}.json`), "utf8");
|
|
13260
14457
|
const session = JSON.parse(raw);
|
|
13261
14458
|
const messages = session.messages ?? [];
|
|
13262
14459
|
const turns = [];
|
|
@@ -13290,14 +14487,14 @@ __export(cli_exports, {
|
|
|
13290
14487
|
runCostCommand: () => runCostCommand
|
|
13291
14488
|
});
|
|
13292
14489
|
import { readFile as readFile18 } from "fs/promises";
|
|
13293
|
-
import { join as
|
|
13294
|
-
import { homedir as
|
|
14490
|
+
import { join as join31 } from "path";
|
|
14491
|
+
import { homedir as homedir20 } from "os";
|
|
13295
14492
|
function usageDir2() {
|
|
13296
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
13297
|
-
return
|
|
14493
|
+
const xdg = process.env.XDG_DATA_HOME || join31(homedir20(), ".local", "share");
|
|
14494
|
+
return join31(xdg, "kimiflare");
|
|
13298
14495
|
}
|
|
13299
14496
|
function usagePath3() {
|
|
13300
|
-
return
|
|
14497
|
+
return join31(usageDir2(), "usage.json");
|
|
13301
14498
|
}
|
|
13302
14499
|
function today2() {
|
|
13303
14500
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -13399,7 +14596,7 @@ __export(aster_workspaces_exports, {
|
|
|
13399
14596
|
findAsterWorkspace: () => findAsterWorkspace,
|
|
13400
14597
|
loadAsterServerConfig: () => loadAsterServerConfig
|
|
13401
14598
|
});
|
|
13402
|
-
import { readFile as readFile19, realpath as realpath3, stat as
|
|
14599
|
+
import { readFile as readFile19, realpath as realpath3, stat as stat7 } from "fs/promises";
|
|
13403
14600
|
import { isAbsolute as isAbsolute3, relative as relative5, sep as sep3 } from "path";
|
|
13404
14601
|
async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_CONFIG || "/etc/autopilot/aster.json") {
|
|
13405
14602
|
let raw;
|
|
@@ -13441,7 +14638,7 @@ async function loadAsterServerConfig(configPath3 = process.env.AUTOPILOT_ASTER_C
|
|
|
13441
14638
|
let rootPath;
|
|
13442
14639
|
try {
|
|
13443
14640
|
rootPath = await realpath3(workspace.rootPath);
|
|
13444
|
-
if (!(await
|
|
14641
|
+
if (!(await stat7(rootPath)).isDirectory()) throw new Error("not a directory");
|
|
13445
14642
|
} catch {
|
|
13446
14643
|
throw new AsterConfigError();
|
|
13447
14644
|
}
|
|
@@ -13481,16 +14678,16 @@ __export(aster_store_exports, {
|
|
|
13481
14678
|
defaultAsterDbPath: () => defaultAsterDbPath
|
|
13482
14679
|
});
|
|
13483
14680
|
import Database3 from "better-sqlite3";
|
|
13484
|
-
import { createHash as
|
|
13485
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
13486
|
-
import { homedir as
|
|
13487
|
-
import { dirname as
|
|
14681
|
+
import { createHash as createHash4, randomBytes as randomBytes2, randomUUID as randomUUID6 } from "crypto";
|
|
14682
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync8 } from "fs";
|
|
14683
|
+
import { homedir as homedir21 } from "os";
|
|
14684
|
+
import { dirname as dirname15, join as join32 } from "path";
|
|
13488
14685
|
function defaultAsterDbPath() {
|
|
13489
|
-
const root = process.env.XDG_STATE_HOME ||
|
|
13490
|
-
return process.env.AUTOPILOT_ASTER_DB ||
|
|
14686
|
+
const root = process.env.XDG_STATE_HOME || join32(homedir21(), ".local", "state");
|
|
14687
|
+
return process.env.AUTOPILOT_ASTER_DB || join32(root, "autopilot", "aster.db");
|
|
13491
14688
|
}
|
|
13492
14689
|
function hashToken(token) {
|
|
13493
|
-
return
|
|
14690
|
+
return createHash4("sha256").update(token).digest("hex");
|
|
13494
14691
|
}
|
|
13495
14692
|
function cellMappingFromRow(row) {
|
|
13496
14693
|
return {
|
|
@@ -13554,9 +14751,9 @@ var init_aster_store = __esm({
|
|
|
13554
14751
|
AsterStore = class {
|
|
13555
14752
|
db;
|
|
13556
14753
|
constructor(dbPath = defaultAsterDbPath()) {
|
|
13557
|
-
|
|
14754
|
+
mkdirSync8(dirname15(dbPath), { recursive: true, mode: 448 });
|
|
13558
14755
|
try {
|
|
13559
|
-
chmodSync2(
|
|
14756
|
+
chmodSync2(dirname15(dbPath), 448);
|
|
13560
14757
|
} catch {
|
|
13561
14758
|
}
|
|
13562
14759
|
this.db = new Database3(dbPath);
|
|
@@ -13667,8 +14864,8 @@ var init_aster_store = __esm({
|
|
|
13667
14864
|
this.db.close();
|
|
13668
14865
|
}
|
|
13669
14866
|
reserveCellConversation(input) {
|
|
13670
|
-
const keyHash =
|
|
13671
|
-
const fingerprint =
|
|
14867
|
+
const keyHash = createHash4("sha256").update(input.idempotencyKey).digest("hex");
|
|
14868
|
+
const fingerprint = createHash4("sha256").update(JSON.stringify([input.workspaceId, input.model])).digest("hex");
|
|
13672
14869
|
const reserve = this.db.transaction(() => {
|
|
13673
14870
|
const existing = this.db.prepare("SELECT * FROM aster_cell_mappings WHERE credential_id = ? AND create_key_hash = ?").get(input.credentialId, keyHash);
|
|
13674
14871
|
if (existing) {
|
|
@@ -13719,7 +14916,7 @@ var init_aster_store = __esm({
|
|
|
13719
14916
|
const scopes = [...new Set(input.scopes)];
|
|
13720
14917
|
if (scopes.length === 0 || scopes.some((scope) => !VALID_SCOPES.has(scope))) throw new Error("credential scopes are invalid");
|
|
13721
14918
|
if (!Number.isSafeInteger(input.expiresAt) || input.expiresAt <= Date.now()) throw new Error("credential expiry must be in the future");
|
|
13722
|
-
const id =
|
|
14919
|
+
const id = randomUUID6();
|
|
13723
14920
|
const token = `aster_${randomBytes2(32).toString("base64url")}`;
|
|
13724
14921
|
const now2 = Date.now();
|
|
13725
14922
|
this.db.prepare(`INSERT INTO aster_credentials
|
|
@@ -13892,7 +15089,7 @@ var init_aster_store = __esm({
|
|
|
13892
15089
|
}));
|
|
13893
15090
|
}
|
|
13894
15091
|
createApproval(input) {
|
|
13895
|
-
const id =
|
|
15092
|
+
const id = randomUUID6();
|
|
13896
15093
|
const now2 = Date.now();
|
|
13897
15094
|
this.db.prepare(`INSERT INTO aster_approvals
|
|
13898
15095
|
(id, conversation_id, run_id, tool_name, explanation, arguments_json, status, expires_at, created_at)
|
|
@@ -14553,13 +15750,13 @@ var init_openapi = __esm({
|
|
|
14553
15750
|
});
|
|
14554
15751
|
|
|
14555
15752
|
// src/runs/worktrees.ts
|
|
14556
|
-
import { execFile as
|
|
15753
|
+
import { execFile as execFile6 } from "child_process";
|
|
14557
15754
|
import { access as access2, chmod as chmod2, mkdir as mkdir12, realpath as realpath4 } from "fs/promises";
|
|
14558
|
-
import { homedir as
|
|
14559
|
-
import { isAbsolute as isAbsolute4, join as
|
|
15755
|
+
import { homedir as homedir22 } from "os";
|
|
15756
|
+
import { isAbsolute as isAbsolute4, join as join33, parse, relative as relative6, resolve as resolve7, sep as sep4 } from "path";
|
|
14560
15757
|
function defaultWorktreesDir() {
|
|
14561
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
14562
|
-
return
|
|
15758
|
+
const dataHome = process.env.XDG_DATA_HOME || join33(homedir22(), ".local", "share");
|
|
15759
|
+
return join33(dataHome, "autopilot", "worktrees");
|
|
14563
15760
|
}
|
|
14564
15761
|
function isOutside(path) {
|
|
14565
15762
|
return path === ".." || path.startsWith(`..${sep4}`) || isAbsolute4(path);
|
|
@@ -14570,7 +15767,7 @@ function isWithin2(parent, candidate) {
|
|
|
14570
15767
|
}
|
|
14571
15768
|
function runGit(args, cwd) {
|
|
14572
15769
|
return new Promise((resolveOutput, reject) => {
|
|
14573
|
-
|
|
15770
|
+
execFile6("git", args, { cwd, encoding: "utf8", timeout: 3e4, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
|
|
14574
15771
|
if (error) {
|
|
14575
15772
|
const detail = stderr.trim();
|
|
14576
15773
|
reject(new Error(`git ${args[0]} failed${detail ? `: ${detail}` : ""}`, { cause: error }));
|
|
@@ -14610,7 +15807,7 @@ var init_worktrees = __esm({
|
|
|
14610
15807
|
throw new Error("worktree root must be outside the source repository");
|
|
14611
15808
|
}
|
|
14612
15809
|
await chmod2(worktreesRoot, 448);
|
|
14613
|
-
const worktreePath =
|
|
15810
|
+
const worktreePath = join33(worktreesRoot, runId);
|
|
14614
15811
|
try {
|
|
14615
15812
|
await access2(worktreePath);
|
|
14616
15813
|
throw new Error(`worktree path already exists for run ${runId}`);
|
|
@@ -14787,11 +15984,11 @@ __export(openrouter_catalog_exports, {
|
|
|
14787
15984
|
mapOpenRouterModel: () => mapOpenRouterModel
|
|
14788
15985
|
});
|
|
14789
15986
|
import { readFile as readFile20, writeFile as writeFile12, mkdir as mkdir13 } from "fs/promises";
|
|
14790
|
-
import { homedir as
|
|
14791
|
-
import { join as
|
|
15987
|
+
import { homedir as homedir23 } from "os";
|
|
15988
|
+
import { join as join34, dirname as dirname16 } from "path";
|
|
14792
15989
|
function catalogCachePath() {
|
|
14793
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
14794
|
-
return
|
|
15990
|
+
const xdg = process.env.XDG_CONFIG_HOME || join34(homedir23(), ".config");
|
|
15991
|
+
return join34(xdg, "kimiflare", "openrouter-models.json");
|
|
14795
15992
|
}
|
|
14796
15993
|
function perMtok(perToken) {
|
|
14797
15994
|
const n = Number(perToken);
|
|
@@ -14852,7 +16049,7 @@ async function readCache3() {
|
|
|
14852
16049
|
async function writeCache3(models) {
|
|
14853
16050
|
const path = catalogCachePath();
|
|
14854
16051
|
try {
|
|
14855
|
-
await mkdir13(
|
|
16052
|
+
await mkdir13(dirname16(path), { recursive: true });
|
|
14856
16053
|
const cache = { version: CACHE_VERSION, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
|
|
14857
16054
|
await writeFile12(path, JSON.stringify(cache, null, 2), "utf8");
|
|
14858
16055
|
} catch {
|
|
@@ -15083,7 +16280,7 @@ var init_aster_tools = __esm({
|
|
|
15083
16280
|
init_edit();
|
|
15084
16281
|
init_read();
|
|
15085
16282
|
init_write();
|
|
15086
|
-
|
|
16283
|
+
init_paths2();
|
|
15087
16284
|
ASTR_TOOLS = [readTool, writeTool, editTool];
|
|
15088
16285
|
SENSITIVE_NAMES = /* @__PURE__ */ new Set([
|
|
15089
16286
|
".git",
|
|
@@ -15105,9 +16302,9 @@ var init_aster_tools = __esm({
|
|
|
15105
16302
|
|
|
15106
16303
|
// src/server/aster-memory.ts
|
|
15107
16304
|
import Database4 from "better-sqlite3";
|
|
15108
|
-
import { randomUUID as
|
|
15109
|
-
import { chmodSync as chmodSync3, mkdirSync as
|
|
15110
|
-
import { dirname as
|
|
16305
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
16306
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync9 } from "fs";
|
|
16307
|
+
import { dirname as dirname17 } from "path";
|
|
15111
16308
|
function rowToItem(row) {
|
|
15112
16309
|
return {
|
|
15113
16310
|
id: row.id,
|
|
@@ -15160,7 +16357,7 @@ var init_aster_memory = __esm({
|
|
|
15160
16357
|
AsterMemory = class {
|
|
15161
16358
|
constructor(dbPath = defaultAsterDbPath(), options = {}) {
|
|
15162
16359
|
this.options = options;
|
|
15163
|
-
|
|
16360
|
+
mkdirSync9(dirname17(dbPath), { recursive: true, mode: 448 });
|
|
15164
16361
|
this.db = new Database4(dbPath);
|
|
15165
16362
|
this.db.pragma("journal_mode = WAL");
|
|
15166
16363
|
this.db.pragma("busy_timeout = 5000");
|
|
@@ -15224,7 +16421,7 @@ var init_aster_memory = __esm({
|
|
|
15224
16421
|
this.db.prepare("UPDATE aster_memories SET title = ?, content = ?, pinned = ?, updated_at = ? WHERE id = ?").run(title, content, existing.pinned || input.pinned ? 1 : 0, now2, existing.id);
|
|
15225
16422
|
return { item: this.get(existing.id), change: "updated" };
|
|
15226
16423
|
}
|
|
15227
|
-
const id =
|
|
16424
|
+
const id = randomUUID7();
|
|
15228
16425
|
this.db.prepare(`INSERT INTO aster_memories (id, kind, key, title, content, pinned, source_conversation_id, created_at, updated_at)
|
|
15229
16426
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.kind, input.key ?? null, title, content, input.pinned ? 1 : 0, input.sourceConversationId ?? null, now2, now2);
|
|
15230
16427
|
return { item: this.get(id), change: "added" };
|
|
@@ -15436,9 +16633,9 @@ var init_aster_github_proxy = __esm({
|
|
|
15436
16633
|
}
|
|
15437
16634
|
handle(req, res) {
|
|
15438
16635
|
const url = new URL(req.url ?? "/", "http://proxy.local");
|
|
15439
|
-
const
|
|
15440
|
-
const api =
|
|
15441
|
-
if (!
|
|
16636
|
+
const git3 = url.pathname.match(GIT_PATH_RE);
|
|
16637
|
+
const api = git3 ? null : url.pathname.match(API_PATH_RE);
|
|
16638
|
+
if (!git3 && !api) return deny(res, 404, "Only this conversation's repository is reachable");
|
|
15442
16639
|
const grantToken = extractToken(req);
|
|
15443
16640
|
if (!grantToken) {
|
|
15444
16641
|
res.writeHead(401, { "www-authenticate": 'Basic realm="aster-github"', "content-type": "text/plain" });
|
|
@@ -15447,18 +16644,18 @@ var init_aster_github_proxy = __esm({
|
|
|
15447
16644
|
}
|
|
15448
16645
|
const grant = this.options.resolveGrant(grantToken);
|
|
15449
16646
|
if (!grant) return deny(res, 403, "This repository grant is invalid or was revoked");
|
|
15450
|
-
const [, owner, name] =
|
|
16647
|
+
const [, owner, name] = git3 ?? api;
|
|
15451
16648
|
if (`${owner}/${name}`.toLowerCase() !== grant.repository.toLowerCase()) {
|
|
15452
16649
|
return deny(res, 403, `This conversation can only access ${grant.repository}`);
|
|
15453
16650
|
}
|
|
15454
|
-
const upstream =
|
|
16651
|
+
const upstream = git3 ? new URL(`/${owner}/${name}.git/${git3[3]}${url.search}`, this.gitUpstream) : new URL(`/repos/${owner}/${name}${api[3] ?? ""}${url.search}`, this.apiUpstream);
|
|
15455
16652
|
const headers = {};
|
|
15456
16653
|
for (const name2 of FORWARDED_REQUEST_HEADERS) {
|
|
15457
16654
|
const value = req.headers[name2];
|
|
15458
16655
|
if (typeof value === "string") headers[name2] = value;
|
|
15459
16656
|
}
|
|
15460
16657
|
headers["user-agent"] ??= "autopilot-aster";
|
|
15461
|
-
headers.authorization =
|
|
16658
|
+
headers.authorization = git3 ? "Basic " + Buffer.from(`x-access-token:${this.options.token}`).toString("base64") : `Bearer ${this.options.token}`;
|
|
15462
16659
|
const send = upstream.protocol === "https:" ? httpsRequest : httpRequest;
|
|
15463
16660
|
const forward = send(upstream, { method: req.method, headers }, (upstreamRes) => {
|
|
15464
16661
|
const responseHeaders = {};
|
|
@@ -15481,7 +16678,7 @@ var init_aster_github_proxy = __esm({
|
|
|
15481
16678
|
// src/server/aster-push.ts
|
|
15482
16679
|
import Database5 from "better-sqlite3";
|
|
15483
16680
|
import { createSign } from "crypto";
|
|
15484
|
-
import { readFileSync as
|
|
16681
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
15485
16682
|
import { connect } from "http2";
|
|
15486
16683
|
function truncate2(value, limit) {
|
|
15487
16684
|
const clean = value.replace(/\s+/g, " ").trim();
|
|
@@ -15599,7 +16796,7 @@ var init_aster_push = __esm({
|
|
|
15599
16796
|
token() {
|
|
15600
16797
|
const now2 = Math.floor(Date.now() / 1e3);
|
|
15601
16798
|
if (this.jwt && now2 - this.jwt.issuedAt < 50 * 60) return this.jwt.value;
|
|
15602
|
-
this.privateKey ??=
|
|
16799
|
+
this.privateKey ??= readFileSync6(this.options.keyPath, "utf8");
|
|
15603
16800
|
const encode = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
15604
16801
|
const unsigned = `${encode({ alg: "ES256", kid: this.options.keyId })}.${encode({ iss: this.options.teamId, iat: now2 })}`;
|
|
15605
16802
|
const signature = createSign("SHA256").update(unsigned).sign({ key: this.privateKey, dsaEncoding: "ieee-p1363" }).toString("base64url");
|
|
@@ -15611,7 +16808,7 @@ var init_aster_push = __esm({
|
|
|
15611
16808
|
});
|
|
15612
16809
|
|
|
15613
16810
|
// src/server/aster-api.ts
|
|
15614
|
-
import { randomUUID as
|
|
16811
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
15615
16812
|
import { unlink as unlink2 } from "fs/promises";
|
|
15616
16813
|
import { resolve as resolve8 } from "path";
|
|
15617
16814
|
function parseCursor(header, query) {
|
|
@@ -16168,8 +17365,8 @@ var init_aster_api = __esm({
|
|
|
16168
17365
|
};
|
|
16169
17366
|
}
|
|
16170
17367
|
async createConversation(res, store, principal, workspace, model, idempotencyKey, kind, repository) {
|
|
16171
|
-
const candidateId =
|
|
16172
|
-
const candidateSessionId =
|
|
17368
|
+
const candidateId = randomUUID8();
|
|
17369
|
+
const candidateSessionId = randomUUID8();
|
|
16173
17370
|
const reservation = store.reserveCellConversation({
|
|
16174
17371
|
conversationId: candidateId,
|
|
16175
17372
|
credentialId: principal.credentialId,
|
|
@@ -16299,7 +17496,7 @@ var init_aster_api = __esm({
|
|
|
16299
17496
|
sendError(res, 409, "conversation_cell_unavailable", "Conversation cell is not available");
|
|
16300
17497
|
return;
|
|
16301
17498
|
}
|
|
16302
|
-
const runId =
|
|
17499
|
+
const runId = randomUUID8();
|
|
16303
17500
|
if (!idempotent && !store.beginTurn(conversation.id, runId)) {
|
|
16304
17501
|
sendError(res, 409, "conversation_busy", "A turn is already active for this conversation");
|
|
16305
17502
|
return;
|
|
@@ -16747,10 +17944,10 @@ data: ${JSON.stringify(event.data)}
|
|
|
16747
17944
|
});
|
|
16748
17945
|
|
|
16749
17946
|
// src/server/aster-cell-runtime.ts
|
|
16750
|
-
import { execFile as
|
|
17947
|
+
import { execFile as execFile7 } from "child_process";
|
|
16751
17948
|
import { readFile as readFile21 } from "fs/promises";
|
|
16752
|
-
import { promisify as
|
|
16753
|
-
import { randomUUID as
|
|
17949
|
+
import { promisify as promisify6 } from "util";
|
|
17950
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
16754
17951
|
async function writeCellFileChunked(cell, path, content) {
|
|
16755
17952
|
if (Buffer.byteLength(content, "utf8") <= CELL_FILE_WRITE_CHUNK_CHARS) {
|
|
16756
17953
|
await cell.writeFile(path, content, { mode: "0600" });
|
|
@@ -16785,7 +17982,7 @@ async function readBundledCellSdkBundle() {
|
|
|
16785
17982
|
throw new Error("cell_runtime_bundle_unavailable");
|
|
16786
17983
|
}
|
|
16787
17984
|
async function defaultArchiveWorkspace(workspaceRoot) {
|
|
16788
|
-
const { stdout } = await
|
|
17985
|
+
const { stdout } = await execFileAsync5("git", ["-C", workspaceRoot, "archive", "--format=tar", "HEAD"], {
|
|
16789
17986
|
encoding: "buffer",
|
|
16790
17987
|
maxBuffer: 512 * 1024 * 1024
|
|
16791
17988
|
});
|
|
@@ -16833,13 +18030,13 @@ ${redacted.slice(-half)}`;
|
|
|
16833
18030
|
function sleep4(ms) {
|
|
16834
18031
|
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
16835
18032
|
}
|
|
16836
|
-
var
|
|
18033
|
+
var execFileAsync5, CELL_WORKSPACE, CELL_STATE_DIR, CHECKPOINT_MESSAGE_FILE, CELL_RUNTIME_DIR, INSTALLED_RUNTIME_PACKAGE, CELL_RUNTIME_SDK_ENTRY, NOTES_FILE, MEMORY_FILE, MEMORY_EXTRACTION_TIMEOUT_MS, LIVENESS_CHECK_MS, ARTIFACTS_DIR, MAX_ARTIFACTS, MAX_ARTIFACT_BYTES, BRANCH_RE, REPOSITORY_RE, GIT, COMMIT_SHA_RE, MAX_TOOL_OUTPUT_CHARS, MAX_TOOL_INPUT_CHARS, MAX_CHECKPOINTS, CELL_CONTROL_DIR, BRIDGE_MARKER, CONTROL_RUNNER, BRIDGE_RUNNER, HEALTH_TIMEOUT_MS, EVENT_POLL_MS, AsterHotcellRuntime, CELL_FILE_WRITE_CHUNK_CHARS, ARTIFACT_MIME_TYPES;
|
|
16837
18034
|
var init_aster_cell_runtime = __esm({
|
|
16838
18035
|
"src/server/aster-cell-runtime.ts"() {
|
|
16839
18036
|
"use strict";
|
|
16840
18037
|
init_version();
|
|
16841
18038
|
init_aster_tools();
|
|
16842
|
-
|
|
18039
|
+
execFileAsync5 = promisify6(execFile7);
|
|
16843
18040
|
CELL_WORKSPACE = "/workspace";
|
|
16844
18041
|
CELL_STATE_DIR = "/workspace/.aster";
|
|
16845
18042
|
CHECKPOINT_MESSAGE_FILE = `${CELL_STATE_DIR}/checkpoint-message`;
|
|
@@ -16946,7 +18143,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
16946
18143
|
await this.installRuntime(cell);
|
|
16947
18144
|
await this.ensureBridge(cell);
|
|
16948
18145
|
await this.control(cell, "POST", "/rpc", {
|
|
16949
|
-
id:
|
|
18146
|
+
id: randomUUID9(),
|
|
16950
18147
|
type: "new_session",
|
|
16951
18148
|
sessionId: input.sessionId,
|
|
16952
18149
|
config: { model: input.model, cwd: CELL_WORKSPACE }
|
|
@@ -16965,7 +18162,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
16965
18162
|
/** Switch the cell session's model between turns. The bridge persists it for session restore. */
|
|
16966
18163
|
async setModel(cellId, model) {
|
|
16967
18164
|
await this.ensureReady(cellId);
|
|
16968
|
-
await this.controlById(cellId, "POST", "/rpc", { id:
|
|
18165
|
+
await this.controlById(cellId, "POST", "/rpc", { id: randomUUID9(), type: "set_model", modelId: model });
|
|
16969
18166
|
}
|
|
16970
18167
|
/** Reinstall the runtime if the cell's image lost it and restart the bridge if it isn't running. */
|
|
16971
18168
|
async ensureReady(cellId) {
|
|
@@ -17028,7 +18225,7 @@ var init_aster_cell_runtime = __esm({
|
|
|
17028
18225
|
const active = this.activeRuns.get(runId);
|
|
17029
18226
|
if (!active) return;
|
|
17030
18227
|
active.stop();
|
|
17031
|
-
void this.controlById(active.cellId, "POST", "/rpc", { id:
|
|
18228
|
+
void this.controlById(active.cellId, "POST", "/rpc", { id: randomUUID9(), type: "abort" }).catch(() => {
|
|
17032
18229
|
});
|
|
17033
18230
|
}
|
|
17034
18231
|
async runTurn(turn, options = {}) {
|
|
@@ -17127,7 +18324,7 @@ ${turn.userText}` : turn.userText;
|
|
|
17127
18324
|
args: event.args ?? {}
|
|
17128
18325
|
});
|
|
17129
18326
|
await this.controlById(cellId, "POST", "/rpc", {
|
|
17130
|
-
id:
|
|
18327
|
+
id: randomUUID9(),
|
|
17131
18328
|
type: "resolve_permission",
|
|
17132
18329
|
requestId: event.requestId,
|
|
17133
18330
|
decision
|
|
@@ -17255,9 +18452,9 @@ ${turn.userText}` : turn.userText;
|
|
|
17255
18452
|
if (!isSafeArtifactPath(path)) throw new Error("invalid_artifact_path");
|
|
17256
18453
|
const cell = await this.provider.getCell(cellId);
|
|
17257
18454
|
const file = shellQuote2(`${ARTIFACTS_DIR}/${path}`);
|
|
17258
|
-
const
|
|
17259
|
-
if (
|
|
17260
|
-
if (Number(
|
|
18455
|
+
const stat11 = await cell.exec(`[ -f ${file} ] && [ ! -L ${file} ] && stat -c %s -- ${file}`);
|
|
18456
|
+
if (stat11.exitCode !== 0) throw new Error("artifact_not_found");
|
|
18457
|
+
if (Number(stat11.stdout.trim()) > MAX_ARTIFACT_BYTES) throw new Error("artifact_too_large");
|
|
17261
18458
|
const encoded = await cell.exec(`base64 -w0 -- ${file}`);
|
|
17262
18459
|
if (encoded.exitCode !== 0) throw new Error("artifact_not_found");
|
|
17263
18460
|
return { data: Buffer.from(encoded.stdout.trim(), "base64"), mimeType: artifactMimeType(path), name: path.split("/").pop() ?? path };
|
|
@@ -17336,7 +18533,7 @@ ${text}` : text, { mode: "0600" });
|
|
|
17336
18533
|
}
|
|
17337
18534
|
}
|
|
17338
18535
|
async control(cell, method, path, body) {
|
|
17339
|
-
const requestId =
|
|
18536
|
+
const requestId = randomUUID9();
|
|
17340
18537
|
await cell.mkdir(CELL_CONTROL_DIR, { parents: true });
|
|
17341
18538
|
await writeCellFileChunked(cell, `${CELL_CONTROL_DIR}/${requestId}.json`, JSON.stringify({ method, path, body }));
|
|
17342
18539
|
const result2 = await cell.exec(`${CONTROL_RUNNER} ${requestId}`);
|
|
@@ -17552,7 +18749,7 @@ var init_hotcell_provider = __esm({
|
|
|
17552
18749
|
});
|
|
17553
18750
|
|
|
17554
18751
|
// src/server/routes.ts
|
|
17555
|
-
import { randomUUID as
|
|
18752
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
17556
18753
|
import { URL as URL2 } from "url";
|
|
17557
18754
|
import { readFile as readFile22, unlink as unlink3 } from "fs/promises";
|
|
17558
18755
|
import { resolve as resolve9, basename as basename5 } from "path";
|
|
@@ -17567,6 +18764,27 @@ function createHotcellAsterRuntime() {
|
|
|
17567
18764
|
throw error;
|
|
17568
18765
|
}
|
|
17569
18766
|
}
|
|
18767
|
+
async function startSessionTrace(config2, sessionFile, tools, messages) {
|
|
18768
|
+
const trace = createRecorder({
|
|
18769
|
+
enabled: config2.trace?.enabled === true,
|
|
18770
|
+
sessionId: sessionFile.id,
|
|
18771
|
+
root: config2.trace?.root
|
|
18772
|
+
});
|
|
18773
|
+
const systemPrompt = messages.filter((m) => m.role === "system" && typeof m.content === "string").map((m) => m.content).join("\n\n");
|
|
18774
|
+
await emitSessionStart(trace, {
|
|
18775
|
+
cwd: sessionFile.cwd,
|
|
18776
|
+
model: sessionFile.model,
|
|
18777
|
+
mode: "server",
|
|
18778
|
+
config: config2,
|
|
18779
|
+
tools: toOpenAIToolDefs(tools),
|
|
18780
|
+
systemPrompt
|
|
18781
|
+
});
|
|
18782
|
+
return trace;
|
|
18783
|
+
}
|
|
18784
|
+
function traceUserMessage(trace, text, attachments, turnId) {
|
|
18785
|
+
if (!trace?.enabled) return;
|
|
18786
|
+
trace.emit("user_message", { content_blob: trace.blob(text) ?? "", source: "server", attachments }, turnId);
|
|
18787
|
+
}
|
|
17570
18788
|
function parseOptionalBudgetInteger(body, name, minimum = 1) {
|
|
17571
18789
|
if (!Object.hasOwn(body, name)) return void 0;
|
|
17572
18790
|
const value = body[name];
|
|
@@ -17617,8 +18835,8 @@ async function resolveFiles2(filePatterns, cwd) {
|
|
|
17617
18835
|
const resolved = /* @__PURE__ */ new Set();
|
|
17618
18836
|
for (const pattern of filePatterns) {
|
|
17619
18837
|
try {
|
|
17620
|
-
const
|
|
17621
|
-
if (
|
|
18838
|
+
const stat11 = await import("fs/promises").then((m) => m.stat(resolve9(cwd, pattern)));
|
|
18839
|
+
if (stat11.isFile()) {
|
|
17622
18840
|
resolved.add(resolve9(cwd, pattern));
|
|
17623
18841
|
continue;
|
|
17624
18842
|
}
|
|
@@ -17686,7 +18904,8 @@ function setupRoutes(config2, options = {}) {
|
|
|
17686
18904
|
executor: new ToolExecutor(tools),
|
|
17687
18905
|
sseClients: /* @__PURE__ */ new Set(),
|
|
17688
18906
|
runId: run.id,
|
|
17689
|
-
allowedTools
|
|
18907
|
+
allowedTools,
|
|
18908
|
+
trace: await startSessionTrace(config2, sessionFile, tools, sessionFile.messages)
|
|
17690
18909
|
};
|
|
17691
18910
|
activeSessions.set(run.sessionId, active);
|
|
17692
18911
|
activeRuns.set(run.id, active);
|
|
@@ -17874,7 +19093,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
17874
19093
|
const executor = new ToolExecutor(tools);
|
|
17875
19094
|
const { makeSessionId: makeSessionId2 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
17876
19095
|
const sessionId = makeSessionId2(task);
|
|
17877
|
-
const runId =
|
|
19096
|
+
const runId = randomUUID10();
|
|
17878
19097
|
const worktreeManager = new RunWorktreeManager();
|
|
17879
19098
|
let worktree;
|
|
17880
19099
|
if (useWorktree) {
|
|
@@ -17932,7 +19151,10 @@ function setupRoutes(config2, options = {}) {
|
|
|
17932
19151
|
}
|
|
17933
19152
|
throw error;
|
|
17934
19153
|
}
|
|
19154
|
+
const runTrace = await startSessionTrace(config2, sessionFile, tools, messages);
|
|
19155
|
+
traceUserMessage(runTrace, task, 0, makeTurnId());
|
|
17935
19156
|
const active = {
|
|
19157
|
+
trace: runTrace,
|
|
17936
19158
|
sessionFile,
|
|
17937
19159
|
messages,
|
|
17938
19160
|
executor,
|
|
@@ -18114,11 +19336,16 @@ function setupRoutes(config2, options = {}) {
|
|
|
18114
19336
|
const resolvedFiles = await resolveFiles2(files, cwd);
|
|
18115
19337
|
const userContent = await buildUserMessage2(prompt, resolvedFiles, cwd);
|
|
18116
19338
|
messages.push({ role: "user", content: userContent });
|
|
19339
|
+
const trace = await startSessionTrace(config2, sessionFile, ALL_TOOLS, messages);
|
|
19340
|
+
const firstTurnId = makeTurnId();
|
|
19341
|
+
traceUserMessage(trace, prompt, resolvedFiles.length, firstTurnId);
|
|
18117
19342
|
const active = {
|
|
18118
19343
|
sessionFile,
|
|
18119
19344
|
messages,
|
|
18120
19345
|
executor,
|
|
18121
|
-
sseClients: /* @__PURE__ */ new Set()
|
|
19346
|
+
sseClients: /* @__PURE__ */ new Set(),
|
|
19347
|
+
trace,
|
|
19348
|
+
nextTurnId: firstTurnId
|
|
18122
19349
|
};
|
|
18123
19350
|
activeSessions.set(sessionId, active);
|
|
18124
19351
|
launchAgentTurnForSession(active, config2, allowAll);
|
|
@@ -18146,6 +19373,15 @@ function setupRoutes(config2, options = {}) {
|
|
|
18146
19373
|
const resolvedFiles = await resolveFiles2(files, active.sessionFile.cwd);
|
|
18147
19374
|
const userContent = await buildUserMessage2(prompt, resolvedFiles, active.sessionFile.cwd);
|
|
18148
19375
|
active.messages.push({ role: "user", content: userContent });
|
|
19376
|
+
active.nextTurnId = makeTurnId();
|
|
19377
|
+
if (active.trace?.enabled && active.lastTurnId) {
|
|
19378
|
+
active.trace.emit(
|
|
19379
|
+
"outcome",
|
|
19380
|
+
{ kind: "next_message", turn_id: active.lastTurnId, classification: classifyNextMessage(prompt), classifier: "regex" },
|
|
19381
|
+
active.lastTurnId
|
|
19382
|
+
);
|
|
19383
|
+
}
|
|
19384
|
+
traceUserMessage(active.trace, prompt, resolvedFiles.length, active.nextTurnId);
|
|
18149
19385
|
launchAgentTurnForSession(active, config2, allowAll);
|
|
18150
19386
|
json2(res, 202, { sessionId, status: "started" });
|
|
18151
19387
|
return;
|
|
@@ -18160,6 +19396,7 @@ function setupRoutes(config2, options = {}) {
|
|
|
18160
19396
|
wakeScheduler.dispose();
|
|
18161
19397
|
for (const [, active] of activeSessions) {
|
|
18162
19398
|
active.shuttingDown = true;
|
|
19399
|
+
if (active.trace?.enabled) active.trace.emit("session_end", { reason: "exit" }, null);
|
|
18163
19400
|
active.controller?.abort(new Error("server_shutdown"));
|
|
18164
19401
|
for (const client of active.sseClients) {
|
|
18165
19402
|
client.close();
|
|
@@ -18328,6 +19565,9 @@ async function runAgentTurnForSession(active, config2, allowAll) {
|
|
|
18328
19565
|
}
|
|
18329
19566
|
};
|
|
18330
19567
|
const compaction = sessionFileCompactionTarget(sessionFile);
|
|
19568
|
+
const turnId = active.nextTurnId ?? makeTurnId();
|
|
19569
|
+
active.nextTurnId = void 0;
|
|
19570
|
+
active.lastTurnId = turnId;
|
|
18331
19571
|
try {
|
|
18332
19572
|
if (run && runStore) {
|
|
18333
19573
|
const tools = ALL_TOOLS.filter((tool) => active.allowedTools?.has(tool.name));
|
|
@@ -18349,6 +19589,8 @@ async function runAgentTurnForSession(active, config2, allowAll) {
|
|
|
18349
19589
|
preferPullRequests: config2.preferPullRequests,
|
|
18350
19590
|
compaction,
|
|
18351
19591
|
callbacks,
|
|
19592
|
+
trace: active.trace,
|
|
19593
|
+
turnId,
|
|
18352
19594
|
onIterationEnd: async (updatedMessages) => {
|
|
18353
19595
|
sessionFile.messages = updatedMessages;
|
|
18354
19596
|
sessionFile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -18375,7 +19617,9 @@ async function runAgentTurnForSession(active, config2, allowAll) {
|
|
|
18375
19617
|
allowDirectPush: config2.allowDirectPush,
|
|
18376
19618
|
preferPullRequests: config2.preferPullRequests,
|
|
18377
19619
|
compaction,
|
|
18378
|
-
callbacks
|
|
19620
|
+
callbacks,
|
|
19621
|
+
trace: active.trace,
|
|
19622
|
+
turnId
|
|
18379
19623
|
});
|
|
18380
19624
|
}
|
|
18381
19625
|
sessionFile.messages = messages;
|
|
@@ -18427,6 +19671,8 @@ var init_routes = __esm({
|
|
|
18427
19671
|
"use strict";
|
|
18428
19672
|
init_config();
|
|
18429
19673
|
init_llm_auth();
|
|
19674
|
+
init_trace();
|
|
19675
|
+
init_registry2();
|
|
18430
19676
|
init_loop();
|
|
18431
19677
|
init_system_prompt();
|
|
18432
19678
|
init_executor();
|
|
@@ -18559,8 +19805,8 @@ __export(db_exports, {
|
|
|
18559
19805
|
updateMemoryEmbedding: () => updateMemoryEmbedding
|
|
18560
19806
|
});
|
|
18561
19807
|
import Database6 from "better-sqlite3";
|
|
18562
|
-
import { dirname as
|
|
18563
|
-
import { mkdirSync as
|
|
19808
|
+
import { dirname as dirname18 } from "path";
|
|
19809
|
+
import { mkdirSync as mkdirSync10, statSync as statSync4 } from "fs";
|
|
18564
19810
|
function initSchema(db) {
|
|
18565
19811
|
db.exec(`
|
|
18566
19812
|
CREATE TABLE IF NOT EXISTS memories (
|
|
@@ -18644,7 +19890,7 @@ function openMemoryDb(dbPath) {
|
|
|
18644
19890
|
if (dbInstance) {
|
|
18645
19891
|
dbInstance.close();
|
|
18646
19892
|
}
|
|
18647
|
-
|
|
19893
|
+
mkdirSync10(dirname18(dbPath), { recursive: true });
|
|
18648
19894
|
dbInstance = new Database6(dbPath);
|
|
18649
19895
|
dbInstance.pragma("journal_mode = WAL");
|
|
18650
19896
|
dbInstance.pragma("foreign_keys = ON");
|
|
@@ -19778,12 +21024,12 @@ var init_connection = __esm({
|
|
|
19778
21024
|
});
|
|
19779
21025
|
|
|
19780
21026
|
// src/lsp/protocol.ts
|
|
19781
|
-
import { pathToFileURL as pathToFileURL2, fileURLToPath as
|
|
21027
|
+
import { pathToFileURL as pathToFileURL2, fileURLToPath as fileURLToPath5 } from "url";
|
|
19782
21028
|
function toUri(path) {
|
|
19783
21029
|
return pathToFileURL2(path).href;
|
|
19784
21030
|
}
|
|
19785
21031
|
function fromUri(uri) {
|
|
19786
|
-
return
|
|
21032
|
+
return fileURLToPath5(uri);
|
|
19787
21033
|
}
|
|
19788
21034
|
function symbolKindName(kind) {
|
|
19789
21035
|
const names = {
|
|
@@ -20594,7 +21840,7 @@ function makeLspTools(manager) {
|
|
|
20594
21840
|
var init_lsp = __esm({
|
|
20595
21841
|
"src/tools/lsp.ts"() {
|
|
20596
21842
|
"use strict";
|
|
20597
|
-
|
|
21843
|
+
init_paths2();
|
|
20598
21844
|
init_adapter();
|
|
20599
21845
|
}
|
|
20600
21846
|
});
|
|
@@ -20610,11 +21856,11 @@ __export(requesty_catalog_exports, {
|
|
|
20610
21856
|
mapRequestyModel: () => mapRequestyModel
|
|
20611
21857
|
});
|
|
20612
21858
|
import { readFile as readFile23, writeFile as writeFile13, mkdir as mkdir14 } from "fs/promises";
|
|
20613
|
-
import { homedir as
|
|
20614
|
-
import { join as
|
|
21859
|
+
import { homedir as homedir24 } from "os";
|
|
21860
|
+
import { join as join36, dirname as dirname19 } from "path";
|
|
20615
21861
|
function catalogCachePath2() {
|
|
20616
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
20617
|
-
return
|
|
21862
|
+
const xdg = process.env.XDG_CONFIG_HOME || join36(homedir24(), ".config");
|
|
21863
|
+
return join36(xdg, "kimiflare", "requesty-models.json");
|
|
20618
21864
|
}
|
|
20619
21865
|
function isSafeModelId(id) {
|
|
20620
21866
|
return typeof id === "string" && id.length > 0 && !CONTROL_CHARS.test(id);
|
|
@@ -20685,7 +21931,7 @@ async function readCache4() {
|
|
|
20685
21931
|
async function writeCache4(catalog) {
|
|
20686
21932
|
const path = catalogCachePath2();
|
|
20687
21933
|
try {
|
|
20688
|
-
await mkdir14(
|
|
21934
|
+
await mkdir14(dirname19(path), { recursive: true });
|
|
20689
21935
|
const cache = { version: CACHE_VERSION2, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), ...catalog };
|
|
20690
21936
|
await writeFile13(path, JSON.stringify(cache, null, 2), "utf8");
|
|
20691
21937
|
} catch {
|
|
@@ -20777,9 +22023,9 @@ var init_permissions = __esm({
|
|
|
20777
22023
|
|
|
20778
22024
|
// src/sdk/session.ts
|
|
20779
22025
|
import { resolve as resolve10 } from "path";
|
|
20780
|
-
import { homedir as
|
|
20781
|
-
import { join as
|
|
20782
|
-
import { existsSync as
|
|
22026
|
+
import { homedir as homedir25 } from "os";
|
|
22027
|
+
import { join as join37 } from "path";
|
|
22028
|
+
import { existsSync as existsSync7 } from "fs";
|
|
20783
22029
|
async function createAgentSession(opts2) {
|
|
20784
22030
|
const config2 = await resolveSdkConfig(opts2);
|
|
20785
22031
|
if (usesRequesty(llmAuthFromConfig(config2))) await ensureRequestyCatalog();
|
|
@@ -20795,7 +22041,7 @@ async function createAgentSession(opts2) {
|
|
|
20795
22041
|
let memoryManager = null;
|
|
20796
22042
|
const memoryEnabled = opts2.memoryEnabled ?? config2.memoryEnabled ?? false;
|
|
20797
22043
|
if (memoryEnabled) {
|
|
20798
|
-
const dbPath = config2.memoryDbPath ??
|
|
22044
|
+
const dbPath = config2.memoryDbPath ?? join37(homedir25(), ".local", "share", "kimiflare", "memory.db");
|
|
20799
22045
|
memoryManager = new MemoryManager({
|
|
20800
22046
|
dbPath,
|
|
20801
22047
|
...llmAuthFromConfig(config2),
|
|
@@ -20825,7 +22071,7 @@ async function createAgentSession(opts2) {
|
|
|
20825
22071
|
}
|
|
20826
22072
|
let sessionFile;
|
|
20827
22073
|
if (opts2.sessionId) {
|
|
20828
|
-
const filePath =
|
|
22074
|
+
const filePath = join37(sessionsDir(), `${opts2.sessionId}.json`);
|
|
20829
22075
|
try {
|
|
20830
22076
|
sessionFile = await loadSession(filePath);
|
|
20831
22077
|
} catch {
|
|
@@ -20860,6 +22106,19 @@ async function createAgentSession(opts2) {
|
|
|
20860
22106
|
...sessionFile.messages.filter((m) => m.role !== "system")
|
|
20861
22107
|
];
|
|
20862
22108
|
const isNewSession = sessionFile.messages.length === 0;
|
|
22109
|
+
const trace = createRecorder({
|
|
22110
|
+
enabled: config2.trace?.enabled === true,
|
|
22111
|
+
sessionId: sessionFile.id,
|
|
22112
|
+
root: config2.trace?.root
|
|
22113
|
+
});
|
|
22114
|
+
await emitSessionStart(trace, {
|
|
22115
|
+
cwd,
|
|
22116
|
+
model: config2.model,
|
|
22117
|
+
mode: "sdk",
|
|
22118
|
+
config: config2,
|
|
22119
|
+
tools: toOpenAIToolDefs(allTools),
|
|
22120
|
+
systemPrompt
|
|
22121
|
+
});
|
|
20863
22122
|
const session = new InternalSession({
|
|
20864
22123
|
sessionFile,
|
|
20865
22124
|
cwd,
|
|
@@ -20873,7 +22132,8 @@ async function createAgentSession(opts2) {
|
|
|
20873
22132
|
permissionHandler: opts2.permissionHandler,
|
|
20874
22133
|
onKimiMdStale: opts2.onKimiMdStale,
|
|
20875
22134
|
hooks,
|
|
20876
|
-
provider: opts2.provider
|
|
22135
|
+
provider: opts2.provider,
|
|
22136
|
+
trace
|
|
20877
22137
|
});
|
|
20878
22138
|
if (isNewSession) {
|
|
20879
22139
|
await session.save().catch((err) => {
|
|
@@ -20906,6 +22166,8 @@ var init_session = __esm({
|
|
|
20906
22166
|
init_context_budget();
|
|
20907
22167
|
init_config2();
|
|
20908
22168
|
init_permissions();
|
|
22169
|
+
init_trace();
|
|
22170
|
+
init_registry2();
|
|
20909
22171
|
InternalSession = class {
|
|
20910
22172
|
sessionId;
|
|
20911
22173
|
cwd;
|
|
@@ -20921,6 +22183,10 @@ var init_session = __esm({
|
|
|
20921
22183
|
onKimiMdStale;
|
|
20922
22184
|
provider;
|
|
20923
22185
|
hooks;
|
|
22186
|
+
trace;
|
|
22187
|
+
traceCostUsd = 0;
|
|
22188
|
+
/** Turn id of the last turn that ran, for next-message outcome signals. */
|
|
22189
|
+
lastTurnId = null;
|
|
20924
22190
|
listeners = /* @__PURE__ */ new Set();
|
|
20925
22191
|
steerQueue = [];
|
|
20926
22192
|
followUpQueue = [];
|
|
@@ -20961,6 +22227,7 @@ var init_session = __esm({
|
|
|
20961
22227
|
this.onKimiMdStale = opts2.onKimiMdStale;
|
|
20962
22228
|
this.provider = opts2.provider;
|
|
20963
22229
|
this.hooks = opts2.hooks;
|
|
22230
|
+
this.trace = opts2.trace;
|
|
20964
22231
|
this.permissionHandler = opts2.permissionHandler ?? createDefaultPermissionHandler({
|
|
20965
22232
|
mode: this.currentMode,
|
|
20966
22233
|
onRequest: (req) => {
|
|
@@ -21014,6 +22281,22 @@ var init_session = __esm({
|
|
|
21014
22281
|
}
|
|
21015
22282
|
const userMessage = { role: "user", content: userContent };
|
|
21016
22283
|
this.messages.push(userMessage);
|
|
22284
|
+
const turnId = makeTurnId();
|
|
22285
|
+
if (this.trace.enabled) {
|
|
22286
|
+
if (this.lastTurnId) {
|
|
22287
|
+
this.trace.emit(
|
|
22288
|
+
"outcome",
|
|
22289
|
+
{ kind: "next_message", turn_id: this.lastTurnId, classification: classifyNextMessage(text), classifier: "regex" },
|
|
22290
|
+
this.lastTurnId
|
|
22291
|
+
);
|
|
22292
|
+
}
|
|
22293
|
+
this.trace.emit(
|
|
22294
|
+
"user_message",
|
|
22295
|
+
{ content_blob: this.trace.blob(text) ?? "", source: "sdk", attachments: options?.images?.length ?? 0 },
|
|
22296
|
+
turnId
|
|
22297
|
+
);
|
|
22298
|
+
}
|
|
22299
|
+
this.lastTurnId = turnId;
|
|
21017
22300
|
this.emit({ type: "message.start", messageId, role: "user" });
|
|
21018
22301
|
this.emit({ type: "message.end", messageId });
|
|
21019
22302
|
this.isStreaming = true;
|
|
@@ -21021,7 +22304,7 @@ var init_session = __esm({
|
|
|
21021
22304
|
this.abortController = new AbortController();
|
|
21022
22305
|
let succeeded = false;
|
|
21023
22306
|
try {
|
|
21024
|
-
await this.runTurn(mode, options?.maxToolIterations);
|
|
22307
|
+
await this.runTurn(mode, options?.maxToolIterations, turnId);
|
|
21025
22308
|
succeeded = true;
|
|
21026
22309
|
this.isStreaming = false;
|
|
21027
22310
|
this.emit({ type: "status", status: "idle" });
|
|
@@ -21116,6 +22399,9 @@ var init_session = __esm({
|
|
|
21116
22399
|
}
|
|
21117
22400
|
dispose() {
|
|
21118
22401
|
this.disposed = true;
|
|
22402
|
+
if (this.trace.enabled) {
|
|
22403
|
+
this.trace.emit("session_end", { reason: "exit", ...this.traceCostUsd > 0 ? { total_cost_usd: this.traceCostUsd } : {} }, null);
|
|
22404
|
+
}
|
|
21119
22405
|
this.denyPendingPermissions();
|
|
21120
22406
|
this.abortController?.abort();
|
|
21121
22407
|
this.lspManager?.stopAll().catch(() => {
|
|
@@ -21123,7 +22409,7 @@ var init_session = __esm({
|
|
|
21123
22409
|
this.memoryManager?.close();
|
|
21124
22410
|
this.listeners.clear();
|
|
21125
22411
|
}
|
|
21126
|
-
async runTurn(mode, maxToolIterations) {
|
|
22412
|
+
async runTurn(mode, maxToolIterations, turnId = makeTurnId()) {
|
|
21127
22413
|
const signal = this.abortController.signal;
|
|
21128
22414
|
const coauthor = this.config.coauthor !== false ? {
|
|
21129
22415
|
name: this.config.coauthorName || "autopilot",
|
|
@@ -21196,6 +22482,7 @@ var init_session = __esm({
|
|
|
21196
22482
|
});
|
|
21197
22483
|
},
|
|
21198
22484
|
onUsageFinal: (usage, gatewayMeta) => {
|
|
22485
|
+
if (typeof usage.cost === "number") this.traceCostUsd += usage.cost;
|
|
21199
22486
|
this.usage.totalInputTokens += usage.prompt_tokens;
|
|
21200
22487
|
this.usage.totalOutputTokens += usage.completion_tokens;
|
|
21201
22488
|
this.usage.turnCount += 1;
|
|
@@ -21273,6 +22560,8 @@ var init_session = __esm({
|
|
|
21273
22560
|
compaction: this.compaction,
|
|
21274
22561
|
allowDirectPush: this.config.allowDirectPush,
|
|
21275
22562
|
preferPullRequests: this.config.preferPullRequests,
|
|
22563
|
+
trace: this.trace,
|
|
22564
|
+
turnId,
|
|
21276
22565
|
// Steering lands at the next tool boundary, or before the final answer
|
|
21277
22566
|
// ends the turn (the loop continues so the model can respond to it).
|
|
21278
22567
|
drainPendingInput: () => {
|
|
@@ -21281,6 +22570,9 @@ var init_session = __esm({
|
|
|
21281
22570
|
const messageId = `msg_${this.nextMessageId++}`;
|
|
21282
22571
|
this.emit({ type: "message.start", messageId, role: "user" });
|
|
21283
22572
|
this.emit({ type: "message.end", messageId });
|
|
22573
|
+
if (this.trace.enabled) {
|
|
22574
|
+
this.trace.emit("user_message", { content_blob: this.trace.blob(text) ?? "", source: "continuation", attachments: 0 }, turnId);
|
|
22575
|
+
}
|
|
21284
22576
|
return { role: "user", content: text };
|
|
21285
22577
|
});
|
|
21286
22578
|
},
|
|
@@ -21296,7 +22588,7 @@ var init_session = __esm({
|
|
|
21296
22588
|
}
|
|
21297
22589
|
}
|
|
21298
22590
|
});
|
|
21299
|
-
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) =>
|
|
22591
|
+
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync7(join37(this.cwd, name)))) {
|
|
21300
22592
|
this.messages[0] = {
|
|
21301
22593
|
role: "system",
|
|
21302
22594
|
content: buildSystemPrompt({
|
|
@@ -22108,6 +23400,8 @@ var init_builtins = __esm({
|
|
|
22108
23400
|
{ name: "checkpoint", argHint: "[label]", description: "Save current point in session", source: "builtin" },
|
|
22109
23401
|
{ name: "checkpoints", description: "List checkpoints in current session", source: "builtin" },
|
|
22110
23402
|
{ name: "compact", description: "Summarize old turns to free context", source: "builtin" },
|
|
23403
|
+
{ name: "good", description: "Rate the last turn as good (recorded in the local session trace)", source: "builtin" },
|
|
23404
|
+
{ name: "bad", argHint: "[reason]", description: "Rate the last turn as bad (recorded in the local session trace)", source: "builtin" },
|
|
22111
23405
|
{ name: "clear", description: "Clear current conversation", source: "builtin" },
|
|
22112
23406
|
{ name: "fresh", description: "Start a fresh session with a summarized plan or continuation context", source: "builtin" },
|
|
22113
23407
|
{ name: "init", description: "Scan repo and write AGENTS.md", source: "builtin" },
|
|
@@ -22574,7 +23868,9 @@ var init_help_menu = __esm({
|
|
|
22574
23868
|
{ command: "/resume", description: "pick a past conversation" },
|
|
22575
23869
|
{ command: "/compact", description: "summarize old turns to free context" },
|
|
22576
23870
|
{ command: "/clear", description: "clear current conversation" },
|
|
22577
|
-
{ command: "/fresh", description: "reset session and start fresh with the last plan" }
|
|
23871
|
+
{ command: "/fresh", description: "reset session and start fresh with the last plan" },
|
|
23872
|
+
{ command: "/good", description: "rate the last turn good (local session trace)" },
|
|
23873
|
+
{ command: "/bad [reason]", description: "rate the last turn bad (local session trace)", selectable: false }
|
|
22578
23874
|
]
|
|
22579
23875
|
},
|
|
22580
23876
|
{
|
|
@@ -22733,8 +24029,8 @@ __export(app_helpers_exports, {
|
|
|
22733
24029
|
trackRecentFile: () => trackRecentFile
|
|
22734
24030
|
});
|
|
22735
24031
|
import { execSync as execSync3, spawn as spawn6 } from "child_process";
|
|
22736
|
-
import { existsSync as
|
|
22737
|
-
import { join as
|
|
24032
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
|
|
24033
|
+
import { join as join38 } from "path";
|
|
22738
24034
|
import { platform as platform3 } from "os";
|
|
22739
24035
|
function replaceQueuedPrompt(queue2, key, full, display) {
|
|
22740
24036
|
const index = queue2.findIndex((item) => item.key === key);
|
|
@@ -22842,12 +24138,12 @@ function buildFilePickerIgnoreList(cwd) {
|
|
|
22842
24138
|
];
|
|
22843
24139
|
const gitignorePatterns = [];
|
|
22844
24140
|
try {
|
|
22845
|
-
const gitignorePath =
|
|
24141
|
+
const gitignorePath = join38(cwd, ".gitignore");
|
|
22846
24142
|
const stats = statSync5(gitignorePath);
|
|
22847
24143
|
if (stats.size > MAX_GITIGNORE_SIZE) {
|
|
22848
24144
|
return hardcoded;
|
|
22849
24145
|
}
|
|
22850
|
-
const content =
|
|
24146
|
+
const content = readFileSync7(gitignorePath, "utf-8");
|
|
22851
24147
|
for (const line of content.split(/\r?\n/)) {
|
|
22852
24148
|
const trimmed = line.trim();
|
|
22853
24149
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -22981,7 +24277,7 @@ function findImagePaths(text) {
|
|
|
22981
24277
|
let match;
|
|
22982
24278
|
while ((match = quotedRegex.exec(text)) !== null) {
|
|
22983
24279
|
const path = match[1] ?? match[2];
|
|
22984
|
-
if (path && isImagePath(path) &&
|
|
24280
|
+
if (path && isImagePath(path) && existsSync8(path)) {
|
|
22985
24281
|
paths.push(path);
|
|
22986
24282
|
}
|
|
22987
24283
|
}
|
|
@@ -22990,7 +24286,7 @@ function findImagePaths(text) {
|
|
|
22990
24286
|
const processed = remaining.replace(/\\ /g, ESCAPED_SPACE);
|
|
22991
24287
|
for (const token of processed.split(/\s+/)) {
|
|
22992
24288
|
const clean = token.replace(new RegExp(ESCAPED_SPACE, "g"), " ").replace(/^["']|["',;:!?]$/g, "").replace(/[.,;:!?]$/, "");
|
|
22993
|
-
if (clean && isImagePath(clean) &&
|
|
24289
|
+
if (clean && isImagePath(clean) && existsSync8(clean) && !paths.includes(clean)) {
|
|
22994
24290
|
paths.push(clean);
|
|
22995
24291
|
}
|
|
22996
24292
|
}
|
|
@@ -23020,9 +24316,9 @@ var init_app_helpers = __esm({
|
|
|
23020
24316
|
|
|
23021
24317
|
// src/ui/bang-command.ts
|
|
23022
24318
|
import { spawn as spawn7 } from "child_process";
|
|
23023
|
-
import { mkdtemp as mkdtemp2, readFile as readFile24, rm as
|
|
24319
|
+
import { mkdtemp as mkdtemp2, readFile as readFile24, rm as rm4 } from "fs/promises";
|
|
23024
24320
|
import { tmpdir as tmpdir4, platform as platform4 } from "os";
|
|
23025
|
-
import { join as
|
|
24321
|
+
import { join as join39 } from "path";
|
|
23026
24322
|
function registerInkInstance(instance) {
|
|
23027
24323
|
inkInstance = instance;
|
|
23028
24324
|
}
|
|
@@ -23125,8 +24421,8 @@ async function runBangCommand(command, cwd) {
|
|
|
23125
24421
|
const origErr = stderr.write;
|
|
23126
24422
|
const readable = stdin.listeners("readable");
|
|
23127
24423
|
const wasRaw = stdin.isTTY ? stdin.isRaw : false;
|
|
23128
|
-
const logDir2 = isWindows ? null : await mkdtemp2(
|
|
23129
|
-
const logPath = logDir2 ?
|
|
24424
|
+
const logDir2 = isWindows ? null : await mkdtemp2(join39(tmpdir4(), "autopilot-bang-"));
|
|
24425
|
+
const logPath = logDir2 ? join39(logDir2, "out.log") : null;
|
|
23130
24426
|
const viaScript = logPath ? scriptInvocation(command, shell, logPath) : null;
|
|
23131
24427
|
inkInstance?.clear();
|
|
23132
24428
|
origOut.call(stdout, `
|
|
@@ -23170,7 +24466,7 @@ $ ${command}
|
|
|
23170
24466
|
if (captured && logPath) {
|
|
23171
24467
|
output = cleanTerminalOutput(await readFile24(logPath, "utf8").catch(() => ""));
|
|
23172
24468
|
}
|
|
23173
|
-
if (logDir2) await
|
|
24469
|
+
if (logDir2) await rm4(logDir2, { recursive: true, force: true }).catch(() => {
|
|
23174
24470
|
});
|
|
23175
24471
|
return { command, exitCode: result2.code, signal: result2.signal, output };
|
|
23176
24472
|
}
|
|
@@ -25357,9 +26653,9 @@ __export(camouflage_view_exports, {
|
|
|
25357
26653
|
validateCommandName: () => validateCommandName
|
|
25358
26654
|
});
|
|
25359
26655
|
import { execFileSync as execFileSync2, spawn as spawn9 } from "child_process";
|
|
25360
|
-
import { readdir as
|
|
25361
|
-
import { homedir as
|
|
25362
|
-
import { join as
|
|
26656
|
+
import { readdir as readdir6 } from "fs/promises";
|
|
26657
|
+
import { homedir as homedir26 } from "os";
|
|
26658
|
+
import { join as join40, resolve as resolve11 } from "path";
|
|
25363
26659
|
async function loadSdk() {
|
|
25364
26660
|
const sdk = await import("camouflage-tui").catch((err) => {
|
|
25365
26661
|
throw new CamouflageUnavailable(`camouflage-tui is not installed (${err.message})`);
|
|
@@ -25538,10 +26834,10 @@ function truncateText(s, max) {
|
|
|
25538
26834
|
async function listMentionDir(cwd, query) {
|
|
25539
26835
|
const exact = query === "~" || query === "." || query === ".." || query.endsWith("/..");
|
|
25540
26836
|
const dir = exact ? `${query}/` : query.slice(0, query.lastIndexOf("/") + 1);
|
|
25541
|
-
const expanded = dir.startsWith("~") ?
|
|
26837
|
+
const expanded = dir.startsWith("~") ? join40(homedir26(), dir.slice(1)) : dir;
|
|
25542
26838
|
const target = resolve11(cwd, expanded || ".");
|
|
25543
26839
|
try {
|
|
25544
|
-
const items = await
|
|
26840
|
+
const items = await readdir6(target, { withFileTypes: true });
|
|
25545
26841
|
const entries = items.filter((d) => !d.name.startsWith(".")).map((d) => ({ name: d.name, isDir: d.isDirectory() })).sort((a, b) => a.isDir !== b.isDir ? a.isDir ? -1 : 1 : a.name.localeCompare(b.name)).slice(0, 300).map((d) => `${dir}${d.name}${d.isDir ? "/" : ""}`);
|
|
25546
26842
|
return { dir, entries };
|
|
25547
26843
|
} catch {
|
|
@@ -25619,7 +26915,7 @@ function shortModel(id) {
|
|
|
25619
26915
|
return id.includes("/") ? id.slice(id.indexOf("/") + 1) : id;
|
|
25620
26916
|
}
|
|
25621
26917
|
function shortPath(p) {
|
|
25622
|
-
const home =
|
|
26918
|
+
const home = homedir26();
|
|
25623
26919
|
return p === home ? "~" : p.startsWith(home + "/") ? `~${p.slice(home.length)}` : p;
|
|
25624
26920
|
}
|
|
25625
26921
|
function gitBranch(cwd) {
|
|
@@ -27626,7 +28922,7 @@ var init_tool_view = __esm({
|
|
|
27626
28922
|
"use strict";
|
|
27627
28923
|
init_spinner();
|
|
27628
28924
|
init_diff_view();
|
|
27629
|
-
|
|
28925
|
+
init_paths2();
|
|
27630
28926
|
init_theme_context();
|
|
27631
28927
|
init_narrator();
|
|
27632
28928
|
ToolView = React7.memo(function ToolView2({ evt, verbose, isRepeated, intentTier }) {
|
|
@@ -28373,7 +29669,7 @@ function PermissionModal({ tool, args, onDecide, onFeedback }) {
|
|
|
28373
29669
|
);
|
|
28374
29670
|
const handleFeedbackSubmit = useCallback(
|
|
28375
29671
|
(text) => {
|
|
28376
|
-
onDecide(DENY);
|
|
29672
|
+
onDecide(text.trim() ? { ...DENY, feedback: text.trim() } : DENY);
|
|
28377
29673
|
if (text.trim()) {
|
|
28378
29674
|
onFeedback?.(text);
|
|
28379
29675
|
}
|
|
@@ -28889,7 +30185,7 @@ var init_queue_plan_picker = __esm({
|
|
|
28889
30185
|
// src/agent/jev-context.ts
|
|
28890
30186
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
28891
30187
|
import { readFile as readFile25 } from "fs/promises";
|
|
28892
|
-
import { basename as basename6, join as
|
|
30188
|
+
import { basename as basename6, join as join41, resolve as resolve12 } from "path";
|
|
28893
30189
|
function messageText(message2) {
|
|
28894
30190
|
if (typeof message2.content === "string") return message2.content.trim();
|
|
28895
30191
|
if (!Array.isArray(message2.content)) return "";
|
|
@@ -28911,7 +30207,7 @@ function projectRoot(cwd) {
|
|
|
28911
30207
|
}
|
|
28912
30208
|
async function readPackageMetadata(root) {
|
|
28913
30209
|
try {
|
|
28914
|
-
const parsed = JSON.parse(await readFile25(
|
|
30210
|
+
const parsed = JSON.parse(await readFile25(join41(root, "package.json"), "utf8"));
|
|
28915
30211
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
28916
30212
|
const pkg = parsed;
|
|
28917
30213
|
const metadata = {};
|
|
@@ -28928,7 +30224,7 @@ async function readPackageMetadata(root) {
|
|
|
28928
30224
|
async function readLicenseEvidence(root) {
|
|
28929
30225
|
for (const name of ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE", "COPYING"]) {
|
|
28930
30226
|
try {
|
|
28931
|
-
const content = (await readFile25(
|
|
30227
|
+
const content = (await readFile25(join41(root, name), "utf8")).trim();
|
|
28932
30228
|
if (content) return { source: `project license (${name})`, content: content.slice(0, 700) };
|
|
28933
30229
|
} catch {
|
|
28934
30230
|
}
|
|
@@ -30010,8 +31306,8 @@ var init_frontmatter = __esm({
|
|
|
30010
31306
|
});
|
|
30011
31307
|
|
|
30012
31308
|
// src/skills/loader.ts
|
|
30013
|
-
import { readFile as readFile26, readdir as
|
|
30014
|
-
import { join as
|
|
31309
|
+
import { readFile as readFile26, readdir as readdir7, stat as stat8 } from "fs/promises";
|
|
31310
|
+
import { join as join42, extname } from "path";
|
|
30015
31311
|
function normalizeManifest(raw, filePath) {
|
|
30016
31312
|
const name = typeof raw.name === "string" ? raw.name : "";
|
|
30017
31313
|
const description = typeof raw.description === "string" ? raw.description : "";
|
|
@@ -30044,11 +31340,11 @@ async function loadSkillFile(filePath) {
|
|
|
30044
31340
|
}
|
|
30045
31341
|
async function loadSkillsFromDir(dirPath) {
|
|
30046
31342
|
try {
|
|
30047
|
-
const entries = await
|
|
31343
|
+
const entries = await readdir7(dirPath);
|
|
30048
31344
|
const files = [];
|
|
30049
31345
|
for (const entry of entries) {
|
|
30050
|
-
const full =
|
|
30051
|
-
const s = await
|
|
31346
|
+
const full = join42(dirPath, entry);
|
|
31347
|
+
const s = await stat8(full);
|
|
30052
31348
|
if (s.isFile() && extname(entry) === ".md") {
|
|
30053
31349
|
files.push(full);
|
|
30054
31350
|
}
|
|
@@ -30076,11 +31372,11 @@ var init_loader = __esm({
|
|
|
30076
31372
|
|
|
30077
31373
|
// src/skills/manager.ts
|
|
30078
31374
|
import { mkdir as mkdir15, writeFile as writeFile14, unlink as unlink4, readFile as readFile27 } from "fs/promises";
|
|
30079
|
-
import { join as
|
|
31375
|
+
import { join as join43 } from "path";
|
|
30080
31376
|
function getSkillDirs(cwd) {
|
|
30081
31377
|
return {
|
|
30082
|
-
projectDir:
|
|
30083
|
-
globalDir:
|
|
31378
|
+
projectDir: join43(cwd, ".kimiflare", "skills"),
|
|
31379
|
+
globalDir: join43(process.env.HOME ?? "", ".config", "kimiflare", "skills")
|
|
30084
31380
|
};
|
|
30085
31381
|
}
|
|
30086
31382
|
async function listAllSkills(cwd) {
|
|
@@ -30094,7 +31390,7 @@ async function listAllSkills(cwd) {
|
|
|
30094
31390
|
async function createSkill(opts2) {
|
|
30095
31391
|
const dirs = getSkillDirs(opts2.cwd);
|
|
30096
31392
|
const dir = opts2.scope === "project" ? dirs.projectDir : dirs.globalDir;
|
|
30097
|
-
const filepath =
|
|
31393
|
+
const filepath = join43(dir, `${opts2.name}.md`);
|
|
30098
31394
|
const frontmatter = {
|
|
30099
31395
|
name: opts2.name,
|
|
30100
31396
|
enabled: true,
|
|
@@ -30403,14 +31699,14 @@ __export(tui_report_exports, {
|
|
|
30403
31699
|
getCategoryReportText: () => getCategoryReportText
|
|
30404
31700
|
});
|
|
30405
31701
|
import { readFile as readFile28 } from "fs/promises";
|
|
30406
|
-
import { join as
|
|
30407
|
-
import { homedir as
|
|
31702
|
+
import { join as join44 } from "path";
|
|
31703
|
+
import { homedir as homedir27 } from "os";
|
|
30408
31704
|
function usageDir3() {
|
|
30409
|
-
const xdg = process.env.XDG_DATA_HOME ||
|
|
30410
|
-
return
|
|
31705
|
+
const xdg = process.env.XDG_DATA_HOME || join44(homedir27(), ".local", "share");
|
|
31706
|
+
return join44(xdg, "kimiflare");
|
|
30411
31707
|
}
|
|
30412
31708
|
function usagePath4() {
|
|
30413
|
-
return
|
|
31709
|
+
return join44(usageDir3(), "usage.json");
|
|
30414
31710
|
}
|
|
30415
31711
|
function today3() {
|
|
30416
31712
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -30479,7 +31775,7 @@ var init_tui_report = __esm({
|
|
|
30479
31775
|
});
|
|
30480
31776
|
|
|
30481
31777
|
// src/ui/slash-commands.ts
|
|
30482
|
-
import { join as
|
|
31778
|
+
import { join as join45 } from "path";
|
|
30483
31779
|
import QRCode from "qrcode";
|
|
30484
31780
|
function executeFreshStart(ctx, planText, overrideMode, opts2 = {}) {
|
|
30485
31781
|
const oldSessionId = ctx.sessionIdRef.current;
|
|
@@ -30570,6 +31866,28 @@ function modesGate(ctx) {
|
|
|
30570
31866
|
]);
|
|
30571
31867
|
return false;
|
|
30572
31868
|
}
|
|
31869
|
+
function rateLastTurn(ctx, value, reason) {
|
|
31870
|
+
const { mkKey: mkKey2, setEvents } = ctx;
|
|
31871
|
+
const last = ctx.turnHistoryRef.current.at(-1);
|
|
31872
|
+
if (!last) {
|
|
31873
|
+
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "nothing to rate yet \u2014 finish a turn first" }]);
|
|
31874
|
+
return true;
|
|
31875
|
+
}
|
|
31876
|
+
const trace = ctx.traceRef.current;
|
|
31877
|
+
if (!trace.enabled) {
|
|
31878
|
+
setEvents((e) => [
|
|
31879
|
+
...e,
|
|
31880
|
+
{ kind: "info", key: mkKey2(), text: "session tracing is off, so the rating was not recorded (enable with KIMIFLARE_TRACE=1)" }
|
|
31881
|
+
]);
|
|
31882
|
+
return true;
|
|
31883
|
+
}
|
|
31884
|
+
trace.emit("outcome", { kind: "rating", turn_id: last.turnId, value, ...reason ? { reason } : {} }, last.turnId);
|
|
31885
|
+
setEvents((e) => [
|
|
31886
|
+
...e,
|
|
31887
|
+
{ kind: "info", key: mkKey2(), text: `recorded ${value === "good" ? "\u{1F44D} good" : "\u{1F44E} bad"} for the last turn${reason ? `: ${reason}` : ""}` }
|
|
31888
|
+
]);
|
|
31889
|
+
return true;
|
|
31890
|
+
}
|
|
30573
31891
|
function dispatchSlashCommand(ctx, cmd) {
|
|
30574
31892
|
const raw = cmd.trim();
|
|
30575
31893
|
const [head, ...rest] = raw.split(/\s+/);
|
|
@@ -30579,7 +31897,7 @@ function dispatchSlashCommand(ctx, cmd) {
|
|
|
30579
31897
|
if (!handler) return false;
|
|
30580
31898
|
return handler(ctx, rest, arg);
|
|
30581
31899
|
}
|
|
30582
|
-
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleSubagents, handleJev, handleModel, SETTINGS, handleSettings, handleKey, handleMode, handleMultiAgent, handleTheme, handlePlan, handleAuto, handleEdit, handleSkills, handleMemory, handleResume, handleCheckpoint, handleCompact, handleInit, handleUpdate, handleMcp, handleLsp, handleHooks, handleHello, handleInbox, handleLogout, handleCommand, handleRemote, handleHelp, handleChangelogImage, handlers;
|
|
31900
|
+
var handleExit, handleClear, handleFresh, handleReasoning, handleCost, handleShell, handleSubagents, handleJev, handleModel, SETTINGS, handleSettings, handleKey, handleMode, handleMultiAgent, handleTheme, handlePlan, handleAuto, handleEdit, handleSkills, handleMemory, handleResume, handleCheckpoint, handleCompact, handleInit, handleUpdate, handleMcp, handleLsp, handleHooks, handleHello, handleInbox, handleLogout, handleCommand, handleRemote, handleHelp, handleChangelogImage, handleGood, handleBad, handlers;
|
|
30583
31901
|
var init_slash_commands = __esm({
|
|
30584
31902
|
"src/ui/slash-commands.ts"() {
|
|
30585
31903
|
"use strict";
|
|
@@ -30602,7 +31920,7 @@ var init_slash_commands = __esm({
|
|
|
30602
31920
|
init_executor();
|
|
30603
31921
|
init_recommended();
|
|
30604
31922
|
init_settings();
|
|
30605
|
-
|
|
31923
|
+
init_types2();
|
|
30606
31924
|
init_update_check();
|
|
30607
31925
|
init_version();
|
|
30608
31926
|
init_app_helpers();
|
|
@@ -31389,7 +32707,7 @@ ${lines.join("\n")}` }]);
|
|
|
31389
32707
|
void (async () => {
|
|
31390
32708
|
try {
|
|
31391
32709
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
31392
|
-
const file = await loadSession(
|
|
32710
|
+
const file = await loadSession(join45(sessionsDir3(), `${currentId}.json`));
|
|
31393
32711
|
const cps = file.checkpoints ?? [];
|
|
31394
32712
|
if (cps.length === 0) {
|
|
31395
32713
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "no checkpoints in this session" }]);
|
|
@@ -31434,7 +32752,7 @@ ${lines.join("\n")}` }]);
|
|
|
31434
32752
|
try {
|
|
31435
32753
|
ctx.ensureSessionId();
|
|
31436
32754
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
31437
|
-
const filePath =
|
|
32755
|
+
const filePath = join45(sessionsDir3(), `${ctx.sessionIdRef.current}.json`);
|
|
31438
32756
|
await addCheckpoint(filePath, cp);
|
|
31439
32757
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: `checkpoint saved: "${label}"` }]);
|
|
31440
32758
|
} catch (e) {
|
|
@@ -32025,6 +33343,8 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
32025
33343
|
});
|
|
32026
33344
|
return true;
|
|
32027
33345
|
};
|
|
33346
|
+
handleGood = (ctx, rest) => rateLastTurn(ctx, "good", rest.join(" ").trim());
|
|
33347
|
+
handleBad = (ctx, rest) => rateLastTurn(ctx, "bad", rest.join(" ").trim());
|
|
32028
33348
|
handlers = {
|
|
32029
33349
|
"/exit": handleExit,
|
|
32030
33350
|
"/clear": handleClear,
|
|
@@ -32048,6 +33368,8 @@ project: ${projectSettingsPath(cwd)}`
|
|
|
32048
33368
|
"/resume": handleResume,
|
|
32049
33369
|
"/checkpoint": handleCheckpoint,
|
|
32050
33370
|
"/compact": handleCompact,
|
|
33371
|
+
"/good": handleGood,
|
|
33372
|
+
"/bad": handleBad,
|
|
32051
33373
|
"/init": handleInit,
|
|
32052
33374
|
"/update": handleUpdate,
|
|
32053
33375
|
"/mcp": handleMcp,
|
|
@@ -32379,7 +33701,7 @@ __export(openrouter_oauth_exports, {
|
|
|
32379
33701
|
pkceChallenge: () => pkceChallenge,
|
|
32380
33702
|
startLoopbackListener: () => startLoopbackListener
|
|
32381
33703
|
});
|
|
32382
|
-
import { createHash as
|
|
33704
|
+
import { createHash as createHash5, randomBytes as randomBytes3 } from "crypto";
|
|
32383
33705
|
import { createServer as createServer3 } from "http";
|
|
32384
33706
|
import { hostname } from "os";
|
|
32385
33707
|
function createPkce() {
|
|
@@ -32387,7 +33709,7 @@ function createPkce() {
|
|
|
32387
33709
|
return { verifier, challenge: pkceChallenge(verifier) };
|
|
32388
33710
|
}
|
|
32389
33711
|
function pkceChallenge(verifier) {
|
|
32390
|
-
return
|
|
33712
|
+
return createHash5("sha256").update(verifier).digest("base64url");
|
|
32391
33713
|
}
|
|
32392
33714
|
function openRouterAuthPageUrl() {
|
|
32393
33715
|
return (process.env.OPENROUTER_AUTH_URL?.trim() || "https://openrouter.ai/auth").replace(/\/+$/, "");
|
|
@@ -32899,14 +34221,14 @@ var init_frontmatter2 = __esm({
|
|
|
32899
34221
|
|
|
32900
34222
|
// src/commands/loader.ts
|
|
32901
34223
|
import { open, realpath as realpath6 } from "fs/promises";
|
|
32902
|
-
import { homedir as
|
|
32903
|
-
import { join as
|
|
34224
|
+
import { homedir as homedir28 } from "os";
|
|
34225
|
+
import { join as join46, relative as relative10, sep as sep6 } from "path";
|
|
32904
34226
|
function projectCommandsDir(cwd = process.cwd()) {
|
|
32905
|
-
return
|
|
34227
|
+
return join46(cwd, ".kimiflare", "commands");
|
|
32906
34228
|
}
|
|
32907
34229
|
function globalCommandsDir() {
|
|
32908
|
-
const xdg = process.env.XDG_CONFIG_HOME ||
|
|
32909
|
-
return
|
|
34230
|
+
const xdg = process.env.XDG_CONFIG_HOME || join46(homedir28(), ".config");
|
|
34231
|
+
return join46(xdg, "kimiflare", "commands");
|
|
32910
34232
|
}
|
|
32911
34233
|
async function loadCustomCommands(cwd = process.cwd()) {
|
|
32912
34234
|
const warnings = [];
|
|
@@ -33050,7 +34372,7 @@ var init_loader2 = __esm({
|
|
|
33050
34372
|
init_mode();
|
|
33051
34373
|
init_glob();
|
|
33052
34374
|
init_config();
|
|
33053
|
-
|
|
34375
|
+
init_paths2();
|
|
33054
34376
|
init_frontmatter2();
|
|
33055
34377
|
MAX_COMMAND_FILE_BYTES = 256 * 1024;
|
|
33056
34378
|
}
|
|
@@ -33060,7 +34382,7 @@ var init_loader2 = __esm({
|
|
|
33060
34382
|
import { exec } from "child_process";
|
|
33061
34383
|
import { open as open2, realpath as realpath7 } from "fs/promises";
|
|
33062
34384
|
import { isAbsolute as isAbsolute6, relative as relative11, resolve as resolvePathJoin, basename as pathBasename } from "path";
|
|
33063
|
-
import { promisify as
|
|
34385
|
+
import { promisify as promisify7 } from "util";
|
|
33064
34386
|
function tokenizeArgs(s) {
|
|
33065
34387
|
return [...s.matchAll(ARG_TOKEN_RE)].map((match) => {
|
|
33066
34388
|
const token = match[0];
|
|
@@ -33212,8 +34534,8 @@ var execAsync, ARG_TOKEN_RE, POSITIONAL_RE, HAS_POSITIONAL, SHELL_RE, FILE_RE, D
|
|
|
33212
34534
|
var init_renderer2 = __esm({
|
|
33213
34535
|
"src/commands/renderer.ts"() {
|
|
33214
34536
|
"use strict";
|
|
33215
|
-
|
|
33216
|
-
execAsync =
|
|
34537
|
+
init_paths2();
|
|
34538
|
+
execAsync = promisify7(exec);
|
|
33217
34539
|
ARG_TOKEN_RE = /(?:"[^"]*"|'[^']*'|[^\s"']+)/g;
|
|
33218
34540
|
POSITIONAL_RE = /\$(\d+)/g;
|
|
33219
34541
|
HAS_POSITIONAL = /\$\d+/;
|
|
@@ -33288,11 +34610,11 @@ var init_wcag = __esm({
|
|
|
33288
34610
|
});
|
|
33289
34611
|
|
|
33290
34612
|
// src/ui/theme-loader.ts
|
|
33291
|
-
import { readFile as readFile29, readdir as
|
|
33292
|
-
import { join as
|
|
33293
|
-
import { homedir as
|
|
34613
|
+
import { readFile as readFile29, readdir as readdir8 } from "fs/promises";
|
|
34614
|
+
import { join as join47 } from "path";
|
|
34615
|
+
import { homedir as homedir29 } from "os";
|
|
33294
34616
|
function projectThemesDir(cwd = process.cwd()) {
|
|
33295
|
-
return
|
|
34617
|
+
return join47(cwd, ".kimiflare", "themes");
|
|
33296
34618
|
}
|
|
33297
34619
|
function isHexColor(c) {
|
|
33298
34620
|
return /^#[0-9a-fA-F]{6}$/.test(c);
|
|
@@ -33376,12 +34698,12 @@ async function loadThemesFromDir(dir, source) {
|
|
|
33376
34698
|
const errors = [];
|
|
33377
34699
|
let files;
|
|
33378
34700
|
try {
|
|
33379
|
-
files = await
|
|
34701
|
+
files = await readdir8(dir);
|
|
33380
34702
|
} catch {
|
|
33381
34703
|
return { themes, errors };
|
|
33382
34704
|
}
|
|
33383
34705
|
for (const file of files.filter((f) => f.endsWith(".json"))) {
|
|
33384
|
-
const path =
|
|
34706
|
+
const path = join47(dir, file);
|
|
33385
34707
|
let raw;
|
|
33386
34708
|
try {
|
|
33387
34709
|
raw = await readFile29(path, "utf-8");
|
|
@@ -33530,8 +34852,8 @@ var init_theme_loader = __esm({
|
|
|
33530
34852
|
"use strict";
|
|
33531
34853
|
init_wcag();
|
|
33532
34854
|
init_theme();
|
|
33533
|
-
USER_THEMES_DIR =
|
|
33534
|
-
process.env.XDG_CONFIG_HOME ||
|
|
34855
|
+
USER_THEMES_DIR = join47(
|
|
34856
|
+
process.env.XDG_CONFIG_HOME || join47(homedir29(), ".config"),
|
|
33535
34857
|
"kimiflare",
|
|
33536
34858
|
"themes"
|
|
33537
34859
|
);
|
|
@@ -35689,6 +37011,61 @@ function useSessionManager(deps) {
|
|
|
35689
37011
|
setLogSessionId(sessionIdRef.current);
|
|
35690
37012
|
return sessionIdRef.current;
|
|
35691
37013
|
}, []);
|
|
37014
|
+
const traceRef = useRef7(createNoopRecorder());
|
|
37015
|
+
const traceStartedRef = useRef7(false);
|
|
37016
|
+
const turnHistoryRef = useRef7([]);
|
|
37017
|
+
const noteTurnEnded = useCallback6((turnId) => {
|
|
37018
|
+
turnHistoryRef.current.push({ turnId, endedAt: Date.now() });
|
|
37019
|
+
if (turnHistoryRef.current.length > 100) turnHistoryRef.current.shift();
|
|
37020
|
+
}, []);
|
|
37021
|
+
const endTrace = useCallback6((reason) => {
|
|
37022
|
+
const trace = traceRef.current;
|
|
37023
|
+
if (trace.enabled && traceStartedRef.current) trace.emit("session_end", { reason }, null);
|
|
37024
|
+
traceStartedRef.current = false;
|
|
37025
|
+
traceRef.current = createNoopRecorder();
|
|
37026
|
+
}, []);
|
|
37027
|
+
const traceReverted = useCallback6((how, turns) => {
|
|
37028
|
+
const trace = traceRef.current;
|
|
37029
|
+
if (!trace.enabled) return;
|
|
37030
|
+
for (const turn of turns) trace.emit("outcome", { kind: "reverted", turn_id: turn.turnId, how }, turn.turnId);
|
|
37031
|
+
}, []);
|
|
37032
|
+
const ensureTrace = useCallback6(() => {
|
|
37033
|
+
const id = ensureSessionId();
|
|
37034
|
+
const cfgTrace = depsRef.current.cfg?.trace;
|
|
37035
|
+
const wantEnabled = cfgTrace?.enabled === true;
|
|
37036
|
+
const current = traceRef.current;
|
|
37037
|
+
if (current.sessionId === id && current.enabled === wantEnabled) return current;
|
|
37038
|
+
if (current.enabled && traceStartedRef.current) current.emit("session_end", { reason: "exit" }, null);
|
|
37039
|
+
traceStartedRef.current = false;
|
|
37040
|
+
traceRef.current = createRecorder({ enabled: wantEnabled, sessionId: id, root: cfgTrace?.root });
|
|
37041
|
+
return traceRef.current;
|
|
37042
|
+
}, [ensureSessionId]);
|
|
37043
|
+
const ensureTraceStarted = useCallback6(
|
|
37044
|
+
async (info) => {
|
|
37045
|
+
const trace = ensureTrace();
|
|
37046
|
+
if (!trace.enabled || traceStartedRef.current) return trace;
|
|
37047
|
+
traceStartedRef.current = true;
|
|
37048
|
+
await emitSessionStart(trace, {
|
|
37049
|
+
cwd: process.cwd(),
|
|
37050
|
+
model: info.model,
|
|
37051
|
+
mode: info.mode,
|
|
37052
|
+
config: info.config,
|
|
37053
|
+
tools: info.tools,
|
|
37054
|
+
systemPrompt: info.systemPrompt,
|
|
37055
|
+
toolProfile: info.toolProfile
|
|
37056
|
+
});
|
|
37057
|
+
return trace;
|
|
37058
|
+
},
|
|
37059
|
+
[ensureTrace]
|
|
37060
|
+
);
|
|
37061
|
+
React23.useEffect(() => {
|
|
37062
|
+
const onExit = () => endTrace("exit");
|
|
37063
|
+
process.on("exit", onExit);
|
|
37064
|
+
return () => {
|
|
37065
|
+
process.off("exit", onExit);
|
|
37066
|
+
endTrace("exit");
|
|
37067
|
+
};
|
|
37068
|
+
}, [endTrace]);
|
|
35692
37069
|
const saveSessionSafe = useCallback6(async () => {
|
|
35693
37070
|
const d = depsRef.current;
|
|
35694
37071
|
if (!d.cfg) return;
|
|
@@ -35727,11 +37104,18 @@ function useSessionManager(deps) {
|
|
|
35727
37104
|
setResumeProgress(0);
|
|
35728
37105
|
setResumeStage("Loading session file\u2026");
|
|
35729
37106
|
startSmoothProgress(0, 10, 400);
|
|
35730
|
-
const
|
|
37107
|
+
const loaded = checkpointId ? await loadSessionFromCheckpoint(filePath, checkpointId) : null;
|
|
37108
|
+
const file = loaded ? loaded.file : await loadSession(filePath);
|
|
35731
37109
|
setResumeProgress(10);
|
|
35732
37110
|
setResumeStage("Restoring artifact store\u2026");
|
|
35733
37111
|
startSmoothProgress(10, 20, 400);
|
|
35734
37112
|
d.messagesRef.current = file.messages;
|
|
37113
|
+
if (loaded && file.id === sessionIdRef.current) {
|
|
37114
|
+
const since = Date.parse(loaded.checkpoint.timestamp);
|
|
37115
|
+
traceReverted("restore_checkpoint", turnHistoryRef.current.filter((t) => Number.isNaN(since) || t.endedAt > since));
|
|
37116
|
+
}
|
|
37117
|
+
endTrace(checkpointId ? "restore_checkpoint" : "exit");
|
|
37118
|
+
turnHistoryRef.current = [];
|
|
35735
37119
|
sessionIdRef.current = file.id;
|
|
35736
37120
|
setLogSessionId(file.id);
|
|
35737
37121
|
sessionCreatedAtRef.current = file.createdAt;
|
|
@@ -35907,6 +37291,9 @@ ${summary}`
|
|
|
35907
37291
|
[checkpointSession, doResumeSession]
|
|
35908
37292
|
);
|
|
35909
37293
|
const resetSession = useCallback6(() => {
|
|
37294
|
+
traceReverted("clear", turnHistoryRef.current.slice(-2));
|
|
37295
|
+
turnHistoryRef.current = [];
|
|
37296
|
+
endTrace("clear");
|
|
35910
37297
|
sessionIdRef.current = null;
|
|
35911
37298
|
setLogSessionId(null);
|
|
35912
37299
|
sessionCreatedAtRef.current = null;
|
|
@@ -35914,7 +37301,7 @@ ${summary}`
|
|
|
35914
37301
|
const d = depsRef.current;
|
|
35915
37302
|
d.sessionStateRef.current = emptySessionState();
|
|
35916
37303
|
d.artifactStoreRef.current = new ArtifactStore();
|
|
35917
|
-
}, []);
|
|
37304
|
+
}, [endTrace, traceReverted]);
|
|
35918
37305
|
return {
|
|
35919
37306
|
sessionIdRef,
|
|
35920
37307
|
sessionCreatedAtRef,
|
|
@@ -35936,7 +37323,13 @@ ${summary}`
|
|
|
35936
37323
|
doResumeSession,
|
|
35937
37324
|
handleResumePick,
|
|
35938
37325
|
handleCheckpointPick,
|
|
35939
|
-
resetSession
|
|
37326
|
+
resetSession,
|
|
37327
|
+
traceRef,
|
|
37328
|
+
ensureTrace,
|
|
37329
|
+
ensureTraceStarted,
|
|
37330
|
+
endTrace,
|
|
37331
|
+
turnHistoryRef,
|
|
37332
|
+
noteTurnEnded
|
|
35940
37333
|
};
|
|
35941
37334
|
}
|
|
35942
37335
|
var init_use_session_manager = __esm({
|
|
@@ -35948,6 +37341,7 @@ var init_use_session_manager = __esm({
|
|
|
35948
37341
|
init_recall_inject();
|
|
35949
37342
|
init_usage_tracker();
|
|
35950
37343
|
init_log_sink();
|
|
37344
|
+
init_trace();
|
|
35951
37345
|
init_app_helpers();
|
|
35952
37346
|
init_continuation_summary();
|
|
35953
37347
|
init_config();
|
|
@@ -35986,9 +37380,9 @@ var init_resume_progress = __esm({
|
|
|
35986
37380
|
});
|
|
35987
37381
|
|
|
35988
37382
|
// src/agent/supervisor.ts
|
|
35989
|
-
import { readdir as
|
|
35990
|
-
import { createHash as
|
|
35991
|
-
import { resolve as resolve13, join as
|
|
37383
|
+
import { readdir as readdir9, readFile as readFile30, stat as stat9 } from "fs/promises";
|
|
37384
|
+
import { createHash as createHash6 } from "crypto";
|
|
37385
|
+
import { resolve as resolve13, join as join48 } from "path";
|
|
35992
37386
|
var TurnSupervisor;
|
|
35993
37387
|
var init_supervisor = __esm({
|
|
35994
37388
|
"src/agent/supervisor.ts"() {
|
|
@@ -36346,6 +37740,7 @@ function interruptTurn(deps) {
|
|
|
36346
37740
|
...e,
|
|
36347
37741
|
{ kind: "info", key: deps.mkKey(), text: "(interrupted)" }
|
|
36348
37742
|
]);
|
|
37743
|
+
appendStoppedToolResults(deps.messagesRef.current, deps.pendingToolCallsRef.current);
|
|
36349
37744
|
if (!deps.skipPendingToolCleanup) {
|
|
36350
37745
|
for (const [toolId] of deps.pendingToolCallsRef.current) {
|
|
36351
37746
|
deps.updateTool(toolId, { status: "cancelled" });
|
|
@@ -36371,17 +37766,18 @@ function interruptOrExit(deps) {
|
|
|
36371
37766
|
var init_input_handlers = __esm({
|
|
36372
37767
|
"src/ui/input-handlers.ts"() {
|
|
36373
37768
|
"use strict";
|
|
37769
|
+
init_messages();
|
|
36374
37770
|
}
|
|
36375
37771
|
});
|
|
36376
37772
|
|
|
36377
37773
|
// src/init/context-generator.ts
|
|
36378
|
-
import { existsSync as
|
|
36379
|
-
import { join as
|
|
37774
|
+
import { existsSync as existsSync9, statSync as statSync6 } from "fs";
|
|
37775
|
+
import { join as join49 } from "path";
|
|
36380
37776
|
function detectFlavor(cwd) {
|
|
36381
37777
|
for (const [flavor, signatures] of Object.entries(FLAVOR_SIGNATURES)) {
|
|
36382
37778
|
if (flavor === "generic") continue;
|
|
36383
37779
|
for (const sig of signatures) {
|
|
36384
|
-
const path =
|
|
37780
|
+
const path = join49(cwd, sig);
|
|
36385
37781
|
if (sig.includes("*")) {
|
|
36386
37782
|
try {
|
|
36387
37783
|
const parts = sig.split("*");
|
|
@@ -36393,7 +37789,7 @@ function detectFlavor(cwd) {
|
|
|
36393
37789
|
}
|
|
36394
37790
|
} catch {
|
|
36395
37791
|
}
|
|
36396
|
-
} else if (
|
|
37792
|
+
} else if (existsSync9(path)) {
|
|
36397
37793
|
return flavor;
|
|
36398
37794
|
}
|
|
36399
37795
|
}
|
|
@@ -36402,14 +37798,14 @@ function detectFlavor(cwd) {
|
|
|
36402
37798
|
}
|
|
36403
37799
|
function findFile(cwd, candidates) {
|
|
36404
37800
|
for (const c of candidates) {
|
|
36405
|
-
if (
|
|
37801
|
+
if (existsSync9(join49(cwd, c))) return c;
|
|
36406
37802
|
}
|
|
36407
37803
|
return null;
|
|
36408
37804
|
}
|
|
36409
37805
|
function findSourceRoots(cwd) {
|
|
36410
37806
|
const roots = [];
|
|
36411
37807
|
for (const r of SOURCE_ROOT_CANDIDATES) {
|
|
36412
|
-
const p =
|
|
37808
|
+
const p = join49(cwd, r);
|
|
36413
37809
|
try {
|
|
36414
37810
|
const s = statSync6(p);
|
|
36415
37811
|
if (s.isDirectory()) roots.push(r);
|
|
@@ -36420,9 +37816,9 @@ function findSourceRoots(cwd) {
|
|
|
36420
37816
|
}
|
|
36421
37817
|
function findCiConfig(cwd) {
|
|
36422
37818
|
for (const c of CI_PATHS) {
|
|
36423
|
-
if (
|
|
37819
|
+
if (existsSync9(join49(cwd, c))) {
|
|
36424
37820
|
try {
|
|
36425
|
-
const s = statSync6(
|
|
37821
|
+
const s = statSync6(join49(cwd, c));
|
|
36426
37822
|
return s.isDirectory() ? c : c;
|
|
36427
37823
|
} catch {
|
|
36428
37824
|
}
|
|
@@ -36559,7 +37955,7 @@ function analyzeProject(cwd) {
|
|
|
36559
37955
|
ciConfig: findCiConfig(cwd),
|
|
36560
37956
|
readme: findFile(cwd, ["README.md", "README.rst", "README.txt", "Readme.md"]),
|
|
36561
37957
|
sourceRoots: findSourceRoots(cwd),
|
|
36562
|
-
hasGit:
|
|
37958
|
+
hasGit: existsSync9(join49(cwd, ".git"))
|
|
36563
37959
|
};
|
|
36564
37960
|
}
|
|
36565
37961
|
function bashDiscoveryCommands(profile) {
|
|
@@ -36724,7 +38120,7 @@ Aim for 100\u2013200 lines total. Use markdown tables where they save space.
|
|
|
36724
38120
|
}
|
|
36725
38121
|
function buildInitPrompt(cwd) {
|
|
36726
38122
|
const existingName = ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].find(
|
|
36727
|
-
(n) =>
|
|
38123
|
+
(n) => existsSync9(join49(cwd, n))
|
|
36728
38124
|
);
|
|
36729
38125
|
const isRefresh = existingName !== void 0;
|
|
36730
38126
|
const targetFilename = existingName ?? "AGENTS.md";
|
|
@@ -36807,8 +38203,8 @@ var init_context_generator = __esm({
|
|
|
36807
38203
|
});
|
|
36808
38204
|
|
|
36809
38205
|
// src/init/run-init.ts
|
|
36810
|
-
import { existsSync as
|
|
36811
|
-
import { join as
|
|
38206
|
+
import { existsSync as existsSync10 } from "fs";
|
|
38207
|
+
import { join as join50 } from "path";
|
|
36812
38208
|
async function runInit(deps) {
|
|
36813
38209
|
const {
|
|
36814
38210
|
cfg,
|
|
@@ -37006,7 +38402,7 @@ async function runInit(deps) {
|
|
|
37006
38402
|
}
|
|
37007
38403
|
}
|
|
37008
38404
|
});
|
|
37009
|
-
if (
|
|
38405
|
+
if (existsSync10(join50(cwd, targetFilename))) {
|
|
37010
38406
|
if (cacheStableRef.current) {
|
|
37011
38407
|
messagesRef.current[1] = {
|
|
37012
38408
|
role: "system",
|
|
@@ -37098,11 +38494,11 @@ var init_run_init = __esm({
|
|
|
37098
38494
|
});
|
|
37099
38495
|
|
|
37100
38496
|
// src/skills/discovery.ts
|
|
37101
|
-
import { readdir as
|
|
37102
|
-
import { join as
|
|
38497
|
+
import { readdir as readdir10, stat as stat10, readFile as readFile31 } from "fs/promises";
|
|
38498
|
+
import { join as join51, extname as extname2 } from "path";
|
|
37103
38499
|
async function dirExists(path) {
|
|
37104
38500
|
try {
|
|
37105
|
-
const s = await
|
|
38501
|
+
const s = await stat10(path);
|
|
37106
38502
|
return s.isDirectory();
|
|
37107
38503
|
} catch {
|
|
37108
38504
|
return false;
|
|
@@ -37110,7 +38506,7 @@ async function dirExists(path) {
|
|
|
37110
38506
|
}
|
|
37111
38507
|
async function fileExists(path) {
|
|
37112
38508
|
try {
|
|
37113
|
-
const s = await
|
|
38509
|
+
const s = await stat10(path);
|
|
37114
38510
|
return s.isFile();
|
|
37115
38511
|
} catch {
|
|
37116
38512
|
return false;
|
|
@@ -37118,20 +38514,20 @@ async function fileExists(path) {
|
|
|
37118
38514
|
}
|
|
37119
38515
|
async function scanSkillDir(dirPath, source) {
|
|
37120
38516
|
if (!await dirExists(dirPath)) return [];
|
|
37121
|
-
const entries = await
|
|
38517
|
+
const entries = await readdir10(dirPath, { withFileTypes: true });
|
|
37122
38518
|
const files = [];
|
|
37123
38519
|
for (const entry of entries) {
|
|
37124
38520
|
if (!entry.isFile()) continue;
|
|
37125
38521
|
if (!SKILL_EXTENSIONS.has(extname2(entry.name))) continue;
|
|
37126
|
-
files.push({ filePath:
|
|
38522
|
+
files.push({ filePath: join51(dirPath, entry.name), source });
|
|
37127
38523
|
}
|
|
37128
38524
|
return files;
|
|
37129
38525
|
}
|
|
37130
38526
|
async function discoverSkills(cwd) {
|
|
37131
|
-
const agentsSkills = await scanSkillDir(
|
|
37132
|
-
const agentsMd = await fileExists(
|
|
37133
|
-
const githubSkills = await scanSkillDir(
|
|
37134
|
-
const kimiflareSkills = await scanSkillDir(
|
|
38527
|
+
const agentsSkills = await scanSkillDir(join51(cwd, ".agents", "skills"), "agents");
|
|
38528
|
+
const agentsMd = await fileExists(join51(cwd, "AGENTS.md")) ? [{ filePath: join51(cwd, "AGENTS.md"), source: "agents-md" }] : [];
|
|
38529
|
+
const githubSkills = await scanSkillDir(join51(cwd, ".github", "skills"), "github");
|
|
38530
|
+
const kimiflareSkills = await scanSkillDir(join51(cwd, ".kimiflare", "skills"), "kimiflare");
|
|
37135
38531
|
const ordered = [...agentsSkills, ...agentsMd, ...githubSkills, ...kimiflareSkills];
|
|
37136
38532
|
return ordered;
|
|
37137
38533
|
}
|
|
@@ -37148,9 +38544,9 @@ var init_discovery = __esm({
|
|
|
37148
38544
|
});
|
|
37149
38545
|
|
|
37150
38546
|
// src/skills/parser.ts
|
|
37151
|
-
import { createHash as
|
|
38547
|
+
import { createHash as createHash7 } from "crypto";
|
|
37152
38548
|
function sha2562(input) {
|
|
37153
|
-
return
|
|
38549
|
+
return createHash7("sha256").update(input).digest("hex");
|
|
37154
38550
|
}
|
|
37155
38551
|
function computeContentHash(rawText, parserVersion) {
|
|
37156
38552
|
return sha2562(`${rawText}
|
|
@@ -37341,8 +38737,8 @@ var init_skills = __esm({
|
|
|
37341
38737
|
});
|
|
37342
38738
|
|
|
37343
38739
|
// src/ui/run-startup-tasks.ts
|
|
37344
|
-
import { existsSync as
|
|
37345
|
-
import { join as
|
|
38740
|
+
import { existsSync as existsSync11 } from "fs";
|
|
38741
|
+
import { join as join52 } from "path";
|
|
37346
38742
|
function runStartupTasks(deps) {
|
|
37347
38743
|
const {
|
|
37348
38744
|
cfg,
|
|
@@ -37356,6 +38752,7 @@ function runStartupTasks(deps) {
|
|
|
37356
38752
|
} = deps;
|
|
37357
38753
|
const auth = llmAuthFromConfig(cfg);
|
|
37358
38754
|
void Promise.resolve().then(() => (init_sessions(), sessions_exports)).then(({ pruneSessions: pruneSessions2 }) => pruneSessions2());
|
|
38755
|
+
void Promise.resolve().then(() => (init_retention(), retention_exports)).then(({ pruneTraces: pruneTraces2 }) => pruneTraces2({ root: cfg.trace?.root }));
|
|
37359
38756
|
void Promise.resolve().then(() => (init_log_sink(), log_sink_exports)).then(({ pruneOldLogs: pruneOldLogs2, isLogSinkEnabled: isLogSinkEnabled2 }) => {
|
|
37360
38757
|
if (!isLogSinkEnabled2()) return;
|
|
37361
38758
|
try {
|
|
@@ -37364,7 +38761,7 @@ function runStartupTasks(deps) {
|
|
|
37364
38761
|
}
|
|
37365
38762
|
});
|
|
37366
38763
|
if (cfg.memoryEnabled) {
|
|
37367
|
-
const dbPath = cfg.memoryDbPath ??
|
|
38764
|
+
const dbPath = cfg.memoryDbPath ?? join52(process.cwd(), ".kimiflare", "memory.db");
|
|
37368
38765
|
const manager = new MemoryManager({
|
|
37369
38766
|
dbPath,
|
|
37370
38767
|
...auth,
|
|
@@ -37396,7 +38793,7 @@ function runStartupTasks(deps) {
|
|
|
37396
38793
|
});
|
|
37397
38794
|
const cwd = process.cwd();
|
|
37398
38795
|
sessionStartRecallRef.current = manager.recall({ text: cwd, repoPath: cwd, limit: 5 });
|
|
37399
|
-
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) =>
|
|
38796
|
+
if (["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync11(join52(cwd, name)))) {
|
|
37400
38797
|
const lastRefresh = manager.getLastKimiMdRefreshTime(cwd);
|
|
37401
38798
|
const driftCount = manager.countHighSignalMemoriesSince(cwd, lastRefresh);
|
|
37402
38799
|
if (driftCount >= 5) {
|
|
@@ -37407,7 +38804,7 @@ function runStartupTasks(deps) {
|
|
|
37407
38804
|
memoryManagerRef.current?.close();
|
|
37408
38805
|
memoryManagerRef.current = null;
|
|
37409
38806
|
}
|
|
37410
|
-
const skillDbPath = cfg.memoryDbPath ??
|
|
38807
|
+
const skillDbPath = cfg.memoryDbPath ?? join52(process.cwd(), ".kimiflare", "memory.db");
|
|
37411
38808
|
const skillDb = getMemoryDb() ?? openMemoryDb(skillDbPath);
|
|
37412
38809
|
initSkillsSchema(skillDb);
|
|
37413
38810
|
void indexSkills({
|
|
@@ -37652,7 +39049,8 @@ async function runCompact(deps) {
|
|
|
37652
39049
|
pendingToolCallsRef,
|
|
37653
39050
|
hooks,
|
|
37654
39051
|
sessionId,
|
|
37655
|
-
supervisorRef
|
|
39052
|
+
supervisorRef,
|
|
39053
|
+
trace
|
|
37656
39054
|
} = deps;
|
|
37657
39055
|
if (busy || supervisorRef.current.isRunning) {
|
|
37658
39056
|
setEvents((e) => [
|
|
@@ -37688,6 +39086,7 @@ async function runCompact(deps) {
|
|
|
37688
39086
|
if (result2.metrics.rawTurnsRemoved === 0) {
|
|
37689
39087
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "nothing to compact yet" }]);
|
|
37690
39088
|
} else {
|
|
39089
|
+
traceCompiledCompaction(trace, result2);
|
|
37691
39090
|
messagesRef.current = result2.newMessages;
|
|
37692
39091
|
sessionStateRef.current = result2.newState;
|
|
37693
39092
|
setEvents(
|
|
@@ -37706,6 +39105,7 @@ async function runCompact(deps) {
|
|
|
37706
39105
|
await saveSessionSafe();
|
|
37707
39106
|
}
|
|
37708
39107
|
} else {
|
|
39108
|
+
const before = messagesRef.current;
|
|
37709
39109
|
const result2 = await summarizeMessagesViaLlm({
|
|
37710
39110
|
...llmAuthFromConfig(cfg),
|
|
37711
39111
|
model: cfg.model,
|
|
@@ -37715,6 +39115,7 @@ async function runCompact(deps) {
|
|
|
37715
39115
|
if (result2.replacedCount === 0) {
|
|
37716
39116
|
setEvents((e) => [...e, { kind: "info", key: mkKey2(), text: "nothing to compact yet" }]);
|
|
37717
39117
|
} else {
|
|
39118
|
+
traceLlmCompaction(trace, before, result2);
|
|
37718
39119
|
messagesRef.current = result2.newMessages;
|
|
37719
39120
|
setEvents(
|
|
37720
39121
|
(e) => compactEventsVisual(
|
|
@@ -37755,12 +39156,13 @@ var init_run_compact = __esm({
|
|
|
37755
39156
|
init_logger();
|
|
37756
39157
|
init_app_helpers();
|
|
37757
39158
|
init_llm_auth();
|
|
39159
|
+
init_compaction();
|
|
37758
39160
|
}
|
|
37759
39161
|
});
|
|
37760
39162
|
|
|
37761
39163
|
// src/commands/save.ts
|
|
37762
39164
|
import { mkdir as mkdir16, writeFile as writeFile15, unlink as unlink5 } from "fs/promises";
|
|
37763
|
-
import { dirname as
|
|
39165
|
+
import { dirname as dirname21 } from "path";
|
|
37764
39166
|
async function saveCustomCommand(opts2) {
|
|
37765
39167
|
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
37766
39168
|
const filepath = `${dir}/${opts2.name}.md`;
|
|
@@ -37771,7 +39173,7 @@ async function saveCustomCommand(opts2) {
|
|
|
37771
39173
|
if (opts2.effort) data.effort = opts2.effort;
|
|
37772
39174
|
const frontmatter = serializeFrontmatter(data);
|
|
37773
39175
|
const content = frontmatter + opts2.template;
|
|
37774
|
-
await mkdir16(
|
|
39176
|
+
await mkdir16(dirname21(filepath), { recursive: true });
|
|
37775
39177
|
await writeFile15(filepath, content, "utf8");
|
|
37776
39178
|
return { filepath };
|
|
37777
39179
|
}
|
|
@@ -37894,9 +39296,9 @@ __export(app_exports, {
|
|
|
37894
39296
|
});
|
|
37895
39297
|
import React25, { useState as useState27, useRef as useRef9, useEffect as useEffect11, useCallback as useCallback8, useMemo as useMemo6 } from "react";
|
|
37896
39298
|
import { Box as Box40, Text as Text41, useApp, useInput as useInput19, useWindowSize as useWindowSize2, render } from "ink";
|
|
37897
|
-
import { existsSync as
|
|
37898
|
-
import { join as
|
|
37899
|
-
import { homedir as
|
|
39299
|
+
import { existsSync as existsSync12 } from "fs";
|
|
39300
|
+
import { join as join53, resolve as resolve14 } from "path";
|
|
39301
|
+
import { homedir as homedir30 } from "os";
|
|
37900
39302
|
import { jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
37901
39303
|
function App({
|
|
37902
39304
|
initialCfg,
|
|
@@ -38153,6 +39555,8 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38153
39555
|
}, []);
|
|
38154
39556
|
const sessionStartRecallRef = useRef9(null);
|
|
38155
39557
|
const kimiMdStaleNudgedRef = useRef9(false);
|
|
39558
|
+
const currentTurnIdRef = useRef9(null);
|
|
39559
|
+
const denyFeedbackRef = useRef9(false);
|
|
38156
39560
|
const sessionPlanRef = useRef9(null);
|
|
38157
39561
|
const planCompletePlanRef = useRef9(null);
|
|
38158
39562
|
const sessionMgr = useSessionManager({
|
|
@@ -38190,7 +39594,11 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38190
39594
|
doResumeSession,
|
|
38191
39595
|
handleResumePick,
|
|
38192
39596
|
handleCheckpointPick,
|
|
38193
|
-
resetSession
|
|
39597
|
+
resetSession,
|
|
39598
|
+
traceRef,
|
|
39599
|
+
ensureTraceStarted,
|
|
39600
|
+
turnHistoryRef,
|
|
39601
|
+
noteTurnEnded
|
|
38194
39602
|
} = sessionMgr;
|
|
38195
39603
|
const pendingTextRef = useRef9(/* @__PURE__ */ new Map());
|
|
38196
39604
|
const flushTimeoutRef = useRef9(null);
|
|
@@ -38216,7 +39624,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38216
39624
|
const exactDirectory = query === "~" || query === "." || query === ".." || query.endsWith("/..");
|
|
38217
39625
|
const prefix = exactDirectory ? `${query.replace(/\/$/, "")}/` : slash >= 0 ? query.slice(0, slash + 1) : "";
|
|
38218
39626
|
const directory = exactDirectory ? query : slash >= 0 ? query.slice(0, slash + 1) : query;
|
|
38219
|
-
const expanded = directory.startsWith("~") ?
|
|
39627
|
+
const expanded = directory.startsWith("~") ? join53(homedir30(), directory.slice(1)) : directory;
|
|
38220
39628
|
const target = resolve14(cwd, expanded || ".");
|
|
38221
39629
|
const entries2 = await glob("*", {
|
|
38222
39630
|
cwd: target,
|
|
@@ -38477,6 +39885,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38477
39885
|
store
|
|
38478
39886
|
});
|
|
38479
39887
|
if (result2.metrics.rawTurnsRemoved > 0) {
|
|
39888
|
+
traceCompiledCompaction(traceRef.current, result2, currentTurnIdRef.current);
|
|
38480
39889
|
sessionStateRef.current = result2.newState;
|
|
38481
39890
|
setEvents((e) => [
|
|
38482
39891
|
...e,
|
|
@@ -38522,6 +39931,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38522
39931
|
signal
|
|
38523
39932
|
});
|
|
38524
39933
|
if (result2.replacedCount > 0) {
|
|
39934
|
+
traceLlmCompaction(traceRef.current, messages, result2, currentTurnIdRef.current);
|
|
38525
39935
|
setEvents((e) => [
|
|
38526
39936
|
...e,
|
|
38527
39937
|
{
|
|
@@ -38668,6 +40078,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38668
40078
|
denyPendingPermission,
|
|
38669
40079
|
pendingToolCallsRef,
|
|
38670
40080
|
updateTool,
|
|
40081
|
+
messagesRef,
|
|
38671
40082
|
setEvents,
|
|
38672
40083
|
mkKey,
|
|
38673
40084
|
saveSessionSafe,
|
|
@@ -38695,7 +40106,8 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38695
40106
|
pendingToolCallsRef,
|
|
38696
40107
|
hooks: hooksManagerRef.current,
|
|
38697
40108
|
sessionId: sessionIdRef.current,
|
|
38698
|
-
supervisorRef
|
|
40109
|
+
supervisorRef,
|
|
40110
|
+
trace: traceRef.current
|
|
38699
40111
|
});
|
|
38700
40112
|
}, [cfg, busy, saveSessionSafe]);
|
|
38701
40113
|
const runInit2 = useCallback8(async () => {
|
|
@@ -38875,7 +40287,9 @@ ${wcagWarnings.join("\n")}` }
|
|
|
38875
40287
|
compiledContextRef,
|
|
38876
40288
|
lastApiErrorRef,
|
|
38877
40289
|
activeScopeRef,
|
|
38878
|
-
sessionPlanRef
|
|
40290
|
+
sessionPlanRef,
|
|
40291
|
+
traceRef,
|
|
40292
|
+
turnHistoryRef
|
|
38879
40293
|
}), [
|
|
38880
40294
|
exit,
|
|
38881
40295
|
busy,
|
|
@@ -39178,6 +40592,8 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39178
40592
|
}
|
|
39179
40593
|
}
|
|
39180
40594
|
messagesRef.current.push({ role: "user", content });
|
|
40595
|
+
const traceUserSource = denyFeedbackRef.current ? "deny_feedback" : "typed";
|
|
40596
|
+
denyFeedbackRef.current = false;
|
|
39181
40597
|
await saveSessionSafe();
|
|
39182
40598
|
if (compiledContextRef.current) {
|
|
39183
40599
|
const { ids, recalled } = recallArtifacts(messagesRef.current, artifactStoreRef.current, sessionStateRef.current);
|
|
@@ -39191,7 +40607,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39191
40607
|
}
|
|
39192
40608
|
}
|
|
39193
40609
|
turnCounterRef.current += 1;
|
|
39194
|
-
if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) =>
|
|
40610
|
+
if (turnCounterRef.current % 15 === 0 && ["AGENTS.md", "KIMI.md", "KIMIFLARE.md", "AGENT.md"].some((name) => existsSync12(join53(process.cwd(), name))) && !kimiMdStale) {
|
|
39195
40611
|
setEvents((e) => [
|
|
39196
40612
|
...e,
|
|
39197
40613
|
{ kind: "info", key: mkKey(), text: "Tip: Rerunning /init occasionally helps autopilot (formerly kimiflare) stay accurate as your project evolves." }
|
|
@@ -39215,7 +40631,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39215
40631
|
};
|
|
39216
40632
|
ensureSessionId();
|
|
39217
40633
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
39218
|
-
const filePath =
|
|
40634
|
+
const filePath = join53(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
39219
40635
|
await addCheckpoint(filePath, cp);
|
|
39220
40636
|
}
|
|
39221
40637
|
const summary = await generateContinuationSummary({
|
|
@@ -39464,6 +40880,34 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39464
40880
|
offered: turnTools.some((tool) => tool.name === "subagent"),
|
|
39465
40881
|
guidance: delegationGuidance.kind
|
|
39466
40882
|
});
|
|
40883
|
+
const turnId = makeTurnId();
|
|
40884
|
+
currentTurnIdRef.current = turnId;
|
|
40885
|
+
const trace = await ensureTraceStarted({
|
|
40886
|
+
tools: toOpenAIToolDefs(turnTools),
|
|
40887
|
+
systemPrompt: messagesRef.current.filter((m) => m.role === "system" && typeof m.content === "string").map((m) => m.content).join("\n\n"),
|
|
40888
|
+
model: overrideModel ?? cfg.model,
|
|
40889
|
+
mode: "tui",
|
|
40890
|
+
config: cfg
|
|
40891
|
+
});
|
|
40892
|
+
if (trace.enabled) {
|
|
40893
|
+
const previousTurn = turnHistoryRef.current.at(-1);
|
|
40894
|
+
if (previousTurn) {
|
|
40895
|
+
trace.emit(
|
|
40896
|
+
"outcome",
|
|
40897
|
+
{ kind: "next_message", turn_id: previousTurn.turnId, classification: classifyNextMessage(trimmed), classifier: "regex" },
|
|
40898
|
+
previousTurn.turnId
|
|
40899
|
+
);
|
|
40900
|
+
}
|
|
40901
|
+
trace.emit(
|
|
40902
|
+
"user_message",
|
|
40903
|
+
{
|
|
40904
|
+
content_blob: trace.blob(typeof content === "string" ? content : trimmed) ?? "",
|
|
40905
|
+
source: traceUserSource,
|
|
40906
|
+
attachments: Array.isArray(content) ? content.filter((p) => p.type !== "text").length : 0
|
|
40907
|
+
},
|
|
40908
|
+
turnId
|
|
40909
|
+
);
|
|
40910
|
+
}
|
|
39467
40911
|
supervisorRef.current.startTurn(
|
|
39468
40912
|
{
|
|
39469
40913
|
...llmAuthFromConfig(cfg),
|
|
@@ -39509,6 +40953,8 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39509
40953
|
},
|
|
39510
40954
|
mode: modeRef.current,
|
|
39511
40955
|
cacheStable: cacheStableRef.current,
|
|
40956
|
+
trace,
|
|
40957
|
+
turnId,
|
|
39512
40958
|
onFileChange: (path, content2) => {
|
|
39513
40959
|
if (content2) {
|
|
39514
40960
|
lspManagerRef.current.notifyChange(path, content2);
|
|
@@ -39523,6 +40969,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39523
40969
|
},
|
|
39524
40970
|
{
|
|
39525
40971
|
onDone: () => {
|
|
40972
|
+
noteTurnEnded(turnId);
|
|
39526
40973
|
void (async () => {
|
|
39527
40974
|
await saveSessionSafe();
|
|
39528
40975
|
if (turnScope.signal.aborted) {
|
|
@@ -39550,6 +40997,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39550
40997
|
store
|
|
39551
40998
|
});
|
|
39552
40999
|
if (result2.metrics.rawTurnsRemoved > 0) {
|
|
41000
|
+
traceCompiledCompaction(traceRef.current, result2, turnId);
|
|
39553
41001
|
messagesRef.current = result2.newMessages;
|
|
39554
41002
|
sessionStateRef.current = result2.newState;
|
|
39555
41003
|
setEvents((e) => [
|
|
@@ -39565,6 +41013,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39565
41013
|
}
|
|
39566
41014
|
} else {
|
|
39567
41015
|
try {
|
|
41016
|
+
const before = messagesRef.current;
|
|
39568
41017
|
const result2 = await summarizeMessagesViaLlm({
|
|
39569
41018
|
...llmAuthFromConfig(cfg),
|
|
39570
41019
|
model: cfg.model,
|
|
@@ -39572,6 +41021,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39572
41021
|
signal: turnScope.signal
|
|
39573
41022
|
});
|
|
39574
41023
|
if (result2.replacedCount > 0) {
|
|
41024
|
+
traceLlmCompaction(traceRef.current, before, result2, turnId);
|
|
39575
41025
|
messagesRef.current = result2.newMessages;
|
|
39576
41026
|
setEvents((e) => [
|
|
39577
41027
|
...e,
|
|
@@ -39637,6 +41087,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39637
41087
|
keepLastTurns: 1
|
|
39638
41088
|
});
|
|
39639
41089
|
if (result2.metrics.rawTurnsRemoved > 0) {
|
|
41090
|
+
traceCompiledCompaction(traceRef.current, result2, turnId);
|
|
39640
41091
|
messagesRef.current = result2.newMessages;
|
|
39641
41092
|
sessionStateRef.current = result2.newState;
|
|
39642
41093
|
setEvents((e) => [
|
|
@@ -39652,6 +41103,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39652
41103
|
}
|
|
39653
41104
|
} else {
|
|
39654
41105
|
try {
|
|
41106
|
+
const before = messagesRef.current;
|
|
39655
41107
|
const result2 = await summarizeMessagesViaLlm({
|
|
39656
41108
|
...llmAuthFromConfig(cfg),
|
|
39657
41109
|
model: cfg.model,
|
|
@@ -39660,6 +41112,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39660
41112
|
signal: turnScope.signal
|
|
39661
41113
|
});
|
|
39662
41114
|
if (result2.replacedCount > 0) {
|
|
41115
|
+
traceLlmCompaction(traceRef.current, before, result2, turnId);
|
|
39663
41116
|
messagesRef.current = result2.newMessages;
|
|
39664
41117
|
setEvents((e) => [
|
|
39665
41118
|
...e,
|
|
@@ -39700,7 +41153,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39700
41153
|
};
|
|
39701
41154
|
ensureSessionId();
|
|
39702
41155
|
const { sessionsDir: sessionsDir3 } = await Promise.resolve().then(() => (init_sessions(), sessions_exports));
|
|
39703
|
-
const filePath =
|
|
41156
|
+
const filePath = join53(sessionsDir3(), `${sessionIdRef.current}.json`);
|
|
39704
41157
|
await addCheckpoint(filePath, cp);
|
|
39705
41158
|
}
|
|
39706
41159
|
const summary = await generateContinuationSummary({
|
|
@@ -39751,15 +41204,9 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39751
41204
|
}
|
|
39752
41205
|
},
|
|
39753
41206
|
onError: async (e) => {
|
|
41207
|
+
noteTurnEnded(turnId);
|
|
39754
41208
|
if (e.name === "AbortError") {
|
|
39755
|
-
|
|
39756
|
-
messagesRef.current.push({
|
|
39757
|
-
role: "tool",
|
|
39758
|
-
tool_call_id: tcId,
|
|
39759
|
-
content: "(stopped)",
|
|
39760
|
-
name: tcName
|
|
39761
|
-
});
|
|
39762
|
-
}
|
|
41209
|
+
appendStoppedToolResults(messagesRef.current, pendingToolCallsRef.current);
|
|
39763
41210
|
setEvents(
|
|
39764
41211
|
(evts) => evts.map((e2) => e2.kind === "tool" && e2.status === "running" ? { ...e2, status: "error", result: "(stopped)" } : e2)
|
|
39765
41212
|
);
|
|
@@ -39782,7 +41229,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
39782
41229
|
}
|
|
39783
41230
|
);
|
|
39784
41231
|
},
|
|
39785
|
-
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateResponseMeta, setShowPlanCompletePicker, runUserShellCommand]
|
|
41232
|
+
[cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateResponseMeta, setShowPlanCompletePicker, runUserShellCommand, ensureTraceStarted]
|
|
39786
41233
|
);
|
|
39787
41234
|
useEffect11(() => {
|
|
39788
41235
|
if (!busy && queuePlanDraft === null && supervisorRef.current.phase === "idle") {
|
|
@@ -40283,7 +41730,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40283
41730
|
lsp: {
|
|
40284
41731
|
servers: cfg?.lspServers ?? {},
|
|
40285
41732
|
scope: lspScope,
|
|
40286
|
-
hasProjectDir:
|
|
41733
|
+
hasProjectDir: existsSync12(join53(process.cwd(), ".kimiflare"))
|
|
40287
41734
|
}
|
|
40288
41735
|
});
|
|
40289
41736
|
});
|
|
@@ -40340,7 +41787,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40340
41787
|
onCommandDelete: handleCommandDelete2,
|
|
40341
41788
|
lspServers: cfg?.lspServers ?? {},
|
|
40342
41789
|
lspScope,
|
|
40343
|
-
hasProjectDir:
|
|
41790
|
+
hasProjectDir: existsSync12(join53(process.cwd(), ".kimiflare")),
|
|
40344
41791
|
onLspSave: handleLspSave2,
|
|
40345
41792
|
themes: themeList(),
|
|
40346
41793
|
onPickTheme: handleThemePick,
|
|
@@ -40411,6 +41858,7 @@ ${result2.output ?? "(output not captured)"}`,
|
|
|
40411
41858
|
args: perm.args,
|
|
40412
41859
|
onDecide: decidePermission2,
|
|
40413
41860
|
onFeedback: (text) => {
|
|
41861
|
+
denyFeedbackRef.current = true;
|
|
40414
41862
|
submitRef.current(text);
|
|
40415
41863
|
}
|
|
40416
41864
|
}
|
|
@@ -40676,6 +42124,8 @@ var init_app = __esm({
|
|
|
40676
42124
|
init_run_startup_tasks();
|
|
40677
42125
|
init_manager_init();
|
|
40678
42126
|
init_run_compact();
|
|
42127
|
+
init_trace();
|
|
42128
|
+
init_registry2();
|
|
40679
42129
|
init_distill();
|
|
40680
42130
|
init_plan_resolver();
|
|
40681
42131
|
init_user_shell();
|
|
@@ -40821,6 +42271,8 @@ init_glob();
|
|
|
40821
42271
|
init_permissions_evaluator();
|
|
40822
42272
|
init_classify();
|
|
40823
42273
|
init_subagent_policy();
|
|
42274
|
+
init_trace();
|
|
42275
|
+
init_registry2();
|
|
40824
42276
|
import { readFile as readFile15 } from "fs/promises";
|
|
40825
42277
|
import { resolve as resolve6, basename as basename3 } from "path";
|
|
40826
42278
|
async function resolveSession(opts2) {
|
|
@@ -40860,8 +42312,8 @@ async function resolveFiles(filePatterns, cwd) {
|
|
|
40860
42312
|
const resolved = /* @__PURE__ */ new Set();
|
|
40861
42313
|
for (const pattern of filePatterns) {
|
|
40862
42314
|
try {
|
|
40863
|
-
const
|
|
40864
|
-
if (
|
|
42315
|
+
const stat11 = await import("fs/promises").then((m) => m.stat(resolve6(cwd, pattern)));
|
|
42316
|
+
if (stat11.isFile()) {
|
|
40865
42317
|
resolved.add(resolve6(cwd, pattern));
|
|
40866
42318
|
continue;
|
|
40867
42319
|
}
|
|
@@ -40955,24 +42407,43 @@ async function runPrintMode(opts2) {
|
|
|
40955
42407
|
});
|
|
40956
42408
|
}
|
|
40957
42409
|
const messages = [];
|
|
42410
|
+
const systemPrompt = buildSystemPrompt({ cwd, tools: workerTools, model: opts2.model, preferPullRequests: opts2.preferPullRequests });
|
|
40958
42411
|
if (isNew || sessionFile.messages.length === 0) {
|
|
40959
|
-
messages.push({
|
|
40960
|
-
role: "system",
|
|
40961
|
-
content: buildSystemPrompt({ cwd, tools: workerTools, model: opts2.model, preferPullRequests: opts2.preferPullRequests })
|
|
40962
|
-
});
|
|
42412
|
+
messages.push({ role: "system", content: systemPrompt });
|
|
40963
42413
|
} else {
|
|
40964
42414
|
const nonSystem = sessionFile.messages.filter(
|
|
40965
42415
|
(m) => m.role !== "system" || typeof m.content === "string" && m.content.startsWith("[compiled session state]")
|
|
40966
42416
|
);
|
|
40967
|
-
messages.push({
|
|
40968
|
-
role: "system",
|
|
40969
|
-
content: buildSystemPrompt({ cwd, tools: workerTools, model: opts2.model, preferPullRequests: opts2.preferPullRequests })
|
|
40970
|
-
});
|
|
42417
|
+
messages.push({ role: "system", content: systemPrompt });
|
|
40971
42418
|
messages.push(...nonSystem);
|
|
40972
42419
|
}
|
|
42420
|
+
const trace = createRecorder({
|
|
42421
|
+
enabled: opts2.trace?.enabled === true,
|
|
42422
|
+
sessionId: sessionFile.id,
|
|
42423
|
+
root: opts2.trace?.root
|
|
42424
|
+
});
|
|
42425
|
+
await emitSessionStart(trace, {
|
|
42426
|
+
cwd,
|
|
42427
|
+
model: opts2.model,
|
|
42428
|
+
mode: "print",
|
|
42429
|
+
config: opts2.traceConfigSnapshot,
|
|
42430
|
+
tools: toOpenAIToolDefs(workerTools),
|
|
42431
|
+
systemPrompt,
|
|
42432
|
+
toolProfile: opts2.workerProfile ?? "full"
|
|
42433
|
+
});
|
|
42434
|
+
let traceCostUsd = 0;
|
|
42435
|
+
let traceEndReason = "exit";
|
|
40973
42436
|
const files = opts2.files ? await resolveFiles(opts2.files, cwd) : [];
|
|
40974
42437
|
const { content: userContent } = await buildUserMessage(opts2.prompt, files, cwd);
|
|
40975
42438
|
messages.push({ role: "user", content: userContent });
|
|
42439
|
+
const turnId = makeTurnId();
|
|
42440
|
+
if (trace.enabled) {
|
|
42441
|
+
trace.emit(
|
|
42442
|
+
"user_message",
|
|
42443
|
+
{ content_blob: trace.blob(opts2.prompt) ?? "", source: "print", attachments: files.length },
|
|
42444
|
+
turnId
|
|
42445
|
+
);
|
|
42446
|
+
}
|
|
40976
42447
|
const controller = new AbortController();
|
|
40977
42448
|
process.on("SIGINT", () => controller.abort());
|
|
40978
42449
|
const format = opts2.format ?? "text";
|
|
@@ -40996,6 +42467,7 @@ async function runPrintMode(opts2) {
|
|
|
40996
42467
|
onUsageFinal: (u, meta) => {
|
|
40997
42468
|
const lookup = opts2.openrouterApiKey && !auth.customEndpoint && meta?.generationId ? { apiKey: opts2.openrouterApiKey, meta } : void 0;
|
|
40998
42469
|
usageWrites.push(recordUsage(sessionFile.id, u, lookup, opts2.model).catch(() => void 0));
|
|
42470
|
+
if (typeof u.cost === "number") traceCostUsd += u.cost;
|
|
40999
42471
|
},
|
|
41000
42472
|
onReasoningDelta: opts2.showReasoning ? (delta) => {
|
|
41001
42473
|
if (format === "text") {
|
|
@@ -41137,7 +42609,9 @@ async function runPrintMode(opts2) {
|
|
|
41137
42609
|
// --continue sessions grow across runs; archive older turns onto the
|
|
41138
42610
|
// session file (saved below) instead of failing on context size.
|
|
41139
42611
|
compaction: sessionFileCompactionTarget(sessionFile),
|
|
41140
|
-
callbacks
|
|
42612
|
+
callbacks,
|
|
42613
|
+
trace,
|
|
42614
|
+
turnId
|
|
41141
42615
|
});
|
|
41142
42616
|
} catch (err) {
|
|
41143
42617
|
if (err instanceof BudgetExhaustedError) {
|
|
@@ -41167,9 +42641,12 @@ async function runPrintMode(opts2) {
|
|
|
41167
42641
|
process.exitCode = 1;
|
|
41168
42642
|
return;
|
|
41169
42643
|
}
|
|
42644
|
+
traceEndReason = "crash";
|
|
41170
42645
|
throw err;
|
|
41171
42646
|
} finally {
|
|
41172
42647
|
await Promise.all(usageWrites);
|
|
42648
|
+
trace.emit("session_end", { reason: traceEndReason, total_cost_usd: traceCostUsd || void 0 }, null);
|
|
42649
|
+
await trace.flush();
|
|
41173
42650
|
}
|
|
41174
42651
|
sessionFile.messages = messages;
|
|
41175
42652
|
sessionFile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -41483,7 +42960,9 @@ To use Requesty instead, set REQUESTY_API_KEY or run autopilot auth requesty`
|
|
|
41483
42960
|
dir: opts.dir,
|
|
41484
42961
|
title: opts.title,
|
|
41485
42962
|
permissions: cfg.permissions,
|
|
41486
|
-
workerProfile: opts.workerProfile
|
|
42963
|
+
workerProfile: opts.workerProfile,
|
|
42964
|
+
trace: cfg.trace,
|
|
42965
|
+
traceConfigSnapshot: cfg
|
|
41487
42966
|
});
|
|
41488
42967
|
return;
|
|
41489
42968
|
}
|