autopilot-ai 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1026 -973
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +3 -0
- package/dist/sdk/index.js +155 -61
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/sdk/index.d.ts
CHANGED
|
@@ -173,6 +173,9 @@ interface KimiConfig {
|
|
|
173
173
|
compiledContext?: boolean;
|
|
174
174
|
/** Number of recent user turns to retain image content; older images are dropped. */
|
|
175
175
|
imageHistoryTurns?: number;
|
|
176
|
+
/** Hard safety ceiling on tool iterations per turn, across automatic
|
|
177
|
+
* 200-call counter resets. Defaults to 1000. */
|
|
178
|
+
maxTotalToolIterations?: number;
|
|
176
179
|
/** Enable local structured memory (SQLite + embeddings). */
|
|
177
180
|
memoryEnabled?: boolean;
|
|
178
181
|
/** Path to memory database. Defaults to .kimiflare/memory.db in repo root, or ~/.local/share/kimiflare/memory.db. */
|
package/dist/sdk/index.js
CHANGED
|
@@ -1169,7 +1169,7 @@ var init_types = __esm({
|
|
|
1169
1169
|
// src/hooks/settings.ts
|
|
1170
1170
|
import { existsSync, readFileSync as readFileSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
1171
1171
|
import { homedir as homedir10 } from "os";
|
|
1172
|
-
import { join as join17, dirname as
|
|
1172
|
+
import { join as join17, dirname as dirname8 } from "path";
|
|
1173
1173
|
import { createHash } from "crypto";
|
|
1174
1174
|
function globalSettingsPath() {
|
|
1175
1175
|
const xdg = process.env.XDG_CONFIG_HOME || join17(homedir10(), ".config");
|
|
@@ -2385,7 +2385,7 @@ var RETENTION = {
|
|
|
2385
2385
|
memoryMaxEntries: 1e3
|
|
2386
2386
|
};
|
|
2387
2387
|
async function rotateJsonl(path, maxBytes, rotations) {
|
|
2388
|
-
const { rename } = await import("fs/promises");
|
|
2388
|
+
const { rename: rename3 } = await import("fs/promises");
|
|
2389
2389
|
let s;
|
|
2390
2390
|
try {
|
|
2391
2391
|
s = await stat(path);
|
|
@@ -2397,7 +2397,7 @@ async function rotateJsonl(path, maxBytes, rotations) {
|
|
|
2397
2397
|
const src = i === 1 ? path : `${path}.${i - 1}`;
|
|
2398
2398
|
const dst = `${path}.${i}`;
|
|
2399
2399
|
try {
|
|
2400
|
-
await
|
|
2400
|
+
await rename3(src, dst);
|
|
2401
2401
|
} catch {
|
|
2402
2402
|
}
|
|
2403
2403
|
}
|
|
@@ -3452,6 +3452,7 @@ function buildSystemPrompt(opts) {
|
|
|
3452
3452
|
}
|
|
3453
3453
|
|
|
3454
3454
|
// src/agent/loop.ts
|
|
3455
|
+
var MAX_LOOP_RECOVERIES = 1;
|
|
3455
3456
|
var BudgetExhaustedError = class extends Error {
|
|
3456
3457
|
constructor(message = "Cumulative input token budget exhausted") {
|
|
3457
3458
|
super(message);
|
|
@@ -3459,7 +3460,7 @@ var BudgetExhaustedError = class extends Error {
|
|
|
3459
3460
|
}
|
|
3460
3461
|
};
|
|
3461
3462
|
var AgentLoopError = class extends Error {
|
|
3462
|
-
constructor(message = "Agent got stuck repeating the same tool calls") {
|
|
3463
|
+
constructor(message = "Agent got stuck repeating the same tool calls and was stopped after a recovery attempt") {
|
|
3463
3464
|
super(message);
|
|
3464
3465
|
this.name = "AgentLoopError";
|
|
3465
3466
|
}
|
|
@@ -3516,6 +3517,12 @@ async function runAgentTurn(opts) {
|
|
|
3516
3517
|
const turnStart = performance.now();
|
|
3517
3518
|
logger.info("turn:start", { sessionId: opts.sessionId, codeMode: opts.codeMode ?? false });
|
|
3518
3519
|
const max = opts.maxToolIterations ?? 200;
|
|
3520
|
+
const limitBehavior = opts.toolLimitBehavior ?? (opts.continueOnLimit ? "continue" : "throw");
|
|
3521
|
+
const requestedCeiling = opts.maxTotalToolIterations;
|
|
3522
|
+
const hardCeiling = Math.max(
|
|
3523
|
+
max,
|
|
3524
|
+
requestedCeiling !== void 0 && Number.isFinite(requestedCeiling) && requestedCeiling > 0 ? Math.floor(requestedCeiling) : max * 5
|
|
3525
|
+
);
|
|
3519
3526
|
const codeMode = opts.codeMode ?? false;
|
|
3520
3527
|
const fireStopHook = async () => {
|
|
3521
3528
|
if (opts.signal.aborted) return;
|
|
@@ -3665,8 +3672,11 @@ IMPORTANT \u2014 explore through code, not direct tools: to read files, run shel
|
|
|
3665
3672
|
const WEB_FETCH_DOMAIN_THRESHOLD = 2;
|
|
3666
3673
|
let cumulativePromptTokens = 0;
|
|
3667
3674
|
let iter = 0;
|
|
3675
|
+
let totalIter = 0;
|
|
3668
3676
|
let budgetExhausted = false;
|
|
3669
3677
|
let loopExhausted = false;
|
|
3678
|
+
let loopRecoveries = 0;
|
|
3679
|
+
let finalizeReason = null;
|
|
3670
3680
|
let currentTasks = [];
|
|
3671
3681
|
let mutatingToolsSinceLastTasksSet = 0;
|
|
3672
3682
|
const MUTATING_TOOLS2 = /* @__PURE__ */ new Set(["write", "edit", "bash"]);
|
|
@@ -3684,36 +3694,43 @@ IMPORTANT \u2014 explore through code, not direct tools: to read files, run shel
|
|
|
3684
3694
|
content: "You have reached the cumulative input token budget for this session. Please synthesize your findings and provide a final summary of what was accomplished."
|
|
3685
3695
|
});
|
|
3686
3696
|
}
|
|
3687
|
-
if (
|
|
3697
|
+
if (finalizeReason === null && totalIter >= hardCeiling) {
|
|
3698
|
+
finalizeReason = "limit_ceiling";
|
|
3688
3699
|
opts.messages.push({
|
|
3689
3700
|
role: "system",
|
|
3690
|
-
content:
|
|
3701
|
+
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.`
|
|
3691
3702
|
});
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
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."
|
|
3700
|
-
});
|
|
3701
|
-
iter = 0;
|
|
3702
|
-
} else {
|
|
3703
|
-
await fireStopHook();
|
|
3704
|
-
return;
|
|
3705
|
-
}
|
|
3706
|
-
} else if (opts.continueOnLimit) {
|
|
3703
|
+
opts.callbacks.onGuardrail?.({
|
|
3704
|
+
kind: "limit_ceiling",
|
|
3705
|
+
message: `Tool-iteration ceiling (${hardCeiling}) reached \u2014 wrapping up the turn with a summary.`,
|
|
3706
|
+
totalIterations: totalIter
|
|
3707
|
+
});
|
|
3708
|
+
} else if (finalizeReason === null && iter >= max) {
|
|
3709
|
+
if (limitBehavior === "continue") {
|
|
3707
3710
|
opts.messages.push({
|
|
3708
3711
|
role: "system",
|
|
3709
3712
|
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."
|
|
3710
3713
|
});
|
|
3711
3714
|
iter = 0;
|
|
3715
|
+
opts.callbacks.onGuardrail?.({
|
|
3716
|
+
kind: "limit_reset",
|
|
3717
|
+
message: `Tool-call limit (${max}) reached \u2014 counter reset automatically (${totalIter}/${hardCeiling} total).`,
|
|
3718
|
+
totalIterations: totalIter
|
|
3719
|
+
});
|
|
3720
|
+
} else if (limitBehavior === "stop") {
|
|
3721
|
+
opts.callbacks.onGuardrail?.({
|
|
3722
|
+
kind: "limit_stopped",
|
|
3723
|
+
message: `Tool-call limit (${max}) reached \u2014 turn stopped.`,
|
|
3724
|
+
totalIterations: totalIter
|
|
3725
|
+
});
|
|
3726
|
+
await fireStopHook();
|
|
3727
|
+
return;
|
|
3712
3728
|
} else {
|
|
3713
3729
|
throw new Error(`kimiflare: tool iteration limit reached (${max})`);
|
|
3714
3730
|
}
|
|
3715
3731
|
}
|
|
3716
3732
|
iter++;
|
|
3733
|
+
totalIter++;
|
|
3717
3734
|
turn++;
|
|
3718
3735
|
const previousMessages = opts.messages.slice();
|
|
3719
3736
|
const toolCalls = [];
|
|
@@ -3852,8 +3869,21 @@ IMPORTANT \u2014 explore through code, not direct tools: to read files, run shel
|
|
|
3852
3869
|
}))
|
|
3853
3870
|
} : {}
|
|
3854
3871
|
};
|
|
3872
|
+
if (finalizeReason !== null) {
|
|
3873
|
+
delete assistantMsg.tool_calls;
|
|
3874
|
+
if (!assistantMsg.content) {
|
|
3875
|
+
assistantMsg.content = finalizeReason === "loop" ? "Stopped: I kept repeating blocked tool calls and could not make further progress on this task." : `Stopped: reached the ${hardCeiling}-iteration safety ceiling for this turn before finishing.`;
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3855
3878
|
opts.messages.push(assistantMsg);
|
|
3856
3879
|
opts.callbacks.onAssistantFinal?.(assistantMsg);
|
|
3880
|
+
if (finalizeReason !== null) {
|
|
3881
|
+
logger.info("turn:finalized", { sessionId: opts.sessionId, reason: finalizeReason, totalIter });
|
|
3882
|
+
if (budgetExhausted) throw new BudgetExhaustedError();
|
|
3883
|
+
await fireStopHook();
|
|
3884
|
+
if (finalizeReason === "loop") throw new AgentLoopError();
|
|
3885
|
+
return;
|
|
3886
|
+
}
|
|
3857
3887
|
if (toolCalls.length === 0) {
|
|
3858
3888
|
if (opts.sessionId && lastUsage) {
|
|
3859
3889
|
void logTurnDebug({
|
|
@@ -4485,30 +4515,30 @@ ${sandboxResult.output}` : sandboxResult.output;
|
|
|
4485
4515
|
throw new BudgetExhaustedError();
|
|
4486
4516
|
}
|
|
4487
4517
|
if (loopExhausted) {
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
role: "system",
|
|
4502
|
-
content: "You were stuck calling the same tools with identical arguments. Please synthesize and conclude your findings so far. Do not call any more tools."
|
|
4503
|
-
});
|
|
4504
|
-
loopExhausted = false;
|
|
4505
|
-
recentToolCalls.length = 0;
|
|
4506
|
-
continue;
|
|
4507
|
-
}
|
|
4508
|
-
await fireStopHook();
|
|
4509
|
-
return;
|
|
4518
|
+
loopExhausted = false;
|
|
4519
|
+
recentToolCalls.length = 0;
|
|
4520
|
+
if (loopRecoveries < MAX_LOOP_RECOVERIES) {
|
|
4521
|
+
loopRecoveries++;
|
|
4522
|
+
opts.messages.push({
|
|
4523
|
+
role: "system",
|
|
4524
|
+
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."
|
|
4525
|
+
});
|
|
4526
|
+
opts.callbacks.onGuardrail?.({
|
|
4527
|
+
kind: "loop_recovery",
|
|
4528
|
+
message: "Loop guardrail: repeated tool calls were blocked \u2014 asked the agent to change approach."
|
|
4529
|
+
});
|
|
4530
|
+
continue;
|
|
4510
4531
|
}
|
|
4511
|
-
|
|
4532
|
+
finalizeReason = "loop";
|
|
4533
|
+
opts.messages.push({
|
|
4534
|
+
role: "system",
|
|
4535
|
+
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."
|
|
4536
|
+
});
|
|
4537
|
+
opts.callbacks.onGuardrail?.({
|
|
4538
|
+
kind: "loop_stopped",
|
|
4539
|
+
message: "Loop guardrail: the agent kept repeating blocked tool calls \u2014 ending the turn with a summary."
|
|
4540
|
+
});
|
|
4541
|
+
continue;
|
|
4512
4542
|
}
|
|
4513
4543
|
}
|
|
4514
4544
|
}
|
|
@@ -6722,6 +6752,7 @@ async function loadConfig() {
|
|
|
6722
6752
|
cacheStablePrompts: persisted.cacheStablePrompts ?? cacheStablePrompts,
|
|
6723
6753
|
compiledContext: persisted.compiledContext ?? compiledContext,
|
|
6724
6754
|
imageHistoryTurns: imageHistoryTurns === void 0 || Number.isNaN(imageHistoryTurns) ? persisted.imageHistoryTurns : imageHistoryTurns,
|
|
6755
|
+
maxTotalToolIterations: readNumberEnv("KIMIFLARE_MAX_TOTAL_TOOL_ITERATIONS") ?? persisted.maxTotalToolIterations,
|
|
6725
6756
|
memoryEnabled: readBooleanEnv("KIMIFLARE_MEMORY_ENABLED") ?? persisted.memoryEnabled ?? false,
|
|
6726
6757
|
memoryDbPath: process.env.KIMIFLARE_MEMORY_DB_PATH ?? persisted.memoryDbPath,
|
|
6727
6758
|
memoryMaxAgeDays: readNumberEnv("KIMIFLARE_MEMORY_MAX_AGE_DAYS") ?? persisted.memoryMaxAgeDays,
|
|
@@ -9505,11 +9536,11 @@ async function loadSession(filePath) {
|
|
|
9505
9536
|
}
|
|
9506
9537
|
|
|
9507
9538
|
// src/usage-tracker.ts
|
|
9508
|
-
import { readFile as readFile8,
|
|
9539
|
+
import { readFile as readFile8, rename as rename2 } from "fs/promises";
|
|
9509
9540
|
import { homedir as homedir8 } from "os";
|
|
9510
9541
|
import { join as join15 } from "path";
|
|
9511
9542
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
9512
|
-
import { randomUUID } from "crypto";
|
|
9543
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
9513
9544
|
|
|
9514
9545
|
// src/pricing.ts
|
|
9515
9546
|
var PRICE_IN_PER_M = 0.95;
|
|
@@ -9530,6 +9561,59 @@ function calculateCost(promptTokens, completionTokens, cachedTokens = 0, model)
|
|
|
9530
9561
|
return { uncachedIn, cachedIn, out, total };
|
|
9531
9562
|
}
|
|
9532
9563
|
|
|
9564
|
+
// src/util/atomic-file.ts
|
|
9565
|
+
import { mkdir as mkdir6, rename, rm, stat as stat4, writeFile as writeFile7 } from "fs/promises";
|
|
9566
|
+
import { dirname as dirname6 } from "path";
|
|
9567
|
+
import { randomUUID } from "crypto";
|
|
9568
|
+
async function writeFileAtomic(path, data) {
|
|
9569
|
+
await mkdir6(dirname6(path), { recursive: true });
|
|
9570
|
+
const tmp = `${path}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
9571
|
+
try {
|
|
9572
|
+
await writeFile7(tmp, data, "utf8");
|
|
9573
|
+
await rename(tmp, path);
|
|
9574
|
+
} catch (err) {
|
|
9575
|
+
await rm(tmp, { force: true }).catch(() => void 0);
|
|
9576
|
+
throw err;
|
|
9577
|
+
}
|
|
9578
|
+
}
|
|
9579
|
+
var LOCK_STALE_MS = 15e3;
|
|
9580
|
+
var LOCK_WAIT_MS = 5e3;
|
|
9581
|
+
var LOCK_RETRY_MS = 25;
|
|
9582
|
+
async function withFileLock(lockPath, fn) {
|
|
9583
|
+
await mkdir6(dirname6(lockPath), { recursive: true });
|
|
9584
|
+
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
9585
|
+
let held = false;
|
|
9586
|
+
while (!held) {
|
|
9587
|
+
try {
|
|
9588
|
+
await mkdir6(lockPath);
|
|
9589
|
+
held = true;
|
|
9590
|
+
} catch (err) {
|
|
9591
|
+
if (err.code !== "EEXIST") break;
|
|
9592
|
+
const age = await stat4(lockPath).then((s) => Date.now() - s.mtimeMs, () => 0);
|
|
9593
|
+
if (age > LOCK_STALE_MS) {
|
|
9594
|
+
await rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
9595
|
+
continue;
|
|
9596
|
+
}
|
|
9597
|
+
if (Date.now() > deadline) break;
|
|
9598
|
+
await new Promise((r) => setTimeout(r, LOCK_RETRY_MS));
|
|
9599
|
+
}
|
|
9600
|
+
}
|
|
9601
|
+
try {
|
|
9602
|
+
return await fn();
|
|
9603
|
+
} finally {
|
|
9604
|
+
if (held) await rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
9605
|
+
}
|
|
9606
|
+
}
|
|
9607
|
+
function recoverJsonPrefix(raw) {
|
|
9608
|
+
for (let i = raw.lastIndexOf("}"); i > 0; i = raw.lastIndexOf("}", i - 1)) {
|
|
9609
|
+
try {
|
|
9610
|
+
return JSON.parse(raw.slice(0, i + 1));
|
|
9611
|
+
} catch {
|
|
9612
|
+
}
|
|
9613
|
+
}
|
|
9614
|
+
return void 0;
|
|
9615
|
+
}
|
|
9616
|
+
|
|
9533
9617
|
// src/usage-tracker.ts
|
|
9534
9618
|
var LOG_VERSION2 = 1;
|
|
9535
9619
|
var usageEvents = new EventEmitter2();
|
|
@@ -9553,21 +9637,29 @@ function cutoffDate(daysBack) {
|
|
|
9553
9637
|
return d.toISOString().slice(0, 10);
|
|
9554
9638
|
}
|
|
9555
9639
|
async function loadLog() {
|
|
9640
|
+
let raw;
|
|
9556
9641
|
try {
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9642
|
+
raw = await readFile8(usagePath(), "utf8");
|
|
9643
|
+
} catch {
|
|
9644
|
+
return { version: LOG_VERSION2, days: [], sessions: [] };
|
|
9645
|
+
}
|
|
9646
|
+
let parsed;
|
|
9647
|
+
try {
|
|
9648
|
+
parsed = JSON.parse(raw);
|
|
9560
9649
|
} catch {
|
|
9650
|
+
await rename2(usagePath(), `${usagePath()}.corrupt-${Date.now()}`).catch(() => void 0);
|
|
9651
|
+
parsed = recoverJsonPrefix(raw);
|
|
9561
9652
|
}
|
|
9653
|
+
if (parsed && parsed.version === LOG_VERSION2) return parsed;
|
|
9562
9654
|
return { version: LOG_VERSION2, days: [], sessions: [] };
|
|
9563
9655
|
}
|
|
9564
9656
|
async function saveLog(log2) {
|
|
9565
|
-
await
|
|
9566
|
-
await writeFile7(usagePath(), JSON.stringify(log2, null, 2), "utf8");
|
|
9657
|
+
await writeFileAtomic(usagePath(), JSON.stringify(log2, null, 2));
|
|
9567
9658
|
}
|
|
9568
9659
|
var writeChain = Promise.resolve();
|
|
9569
9660
|
function withLock(fn) {
|
|
9570
|
-
const
|
|
9661
|
+
const locked = () => withFileLock(`${usagePath()}.lock`, fn);
|
|
9662
|
+
const next = writeChain.then(locked, locked);
|
|
9571
9663
|
writeChain = next.catch(() => void 0);
|
|
9572
9664
|
return next;
|
|
9573
9665
|
}
|
|
@@ -9597,8 +9689,7 @@ async function upsertHistoryDay(day) {
|
|
|
9597
9689
|
entries.push(day);
|
|
9598
9690
|
}
|
|
9599
9691
|
const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
9600
|
-
await
|
|
9601
|
-
await writeFile7(historyPath(), lines, "utf8");
|
|
9692
|
+
await writeFileAtomic(historyPath(), lines);
|
|
9602
9693
|
}
|
|
9603
9694
|
function getOrCreateDay(log2, date) {
|
|
9604
9695
|
let day = log2.days.find((d) => d.date === date);
|
|
@@ -9657,7 +9748,7 @@ async function recordUsage(sessionId, usage, lookup, model) {
|
|
|
9657
9748
|
);
|
|
9658
9749
|
const estimatedCost = cost.total;
|
|
9659
9750
|
const cachedTokens = usage.prompt_tokens_details?.cached_tokens ?? 0;
|
|
9660
|
-
const turnId =
|
|
9751
|
+
const turnId = randomUUID2();
|
|
9661
9752
|
const generationId = lookup?.meta.generationId;
|
|
9662
9753
|
const inlineCost = typeof usage.cost === "number" && Number.isFinite(usage.cost) ? usage.cost : void 0;
|
|
9663
9754
|
await withLock(async () => {
|
|
@@ -9760,7 +9851,7 @@ async function reconcileTurnCost(sessionId, turnId, lookup, fetchImpl2 = fetch,
|
|
|
9760
9851
|
// src/models/openrouter-catalog.ts
|
|
9761
9852
|
import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir7 } from "fs/promises";
|
|
9762
9853
|
import { homedir as homedir9 } from "os";
|
|
9763
|
-
import { join as join16, dirname as
|
|
9854
|
+
import { join as join16, dirname as dirname7 } from "path";
|
|
9764
9855
|
var CACHE_VERSION = 4;
|
|
9765
9856
|
var DEFAULT_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
9766
9857
|
function catalogCachePath() {
|
|
@@ -9826,7 +9917,7 @@ async function readCache() {
|
|
|
9826
9917
|
async function writeCache(models) {
|
|
9827
9918
|
const path = catalogCachePath();
|
|
9828
9919
|
try {
|
|
9829
|
-
await mkdir7(
|
|
9920
|
+
await mkdir7(dirname7(path), { recursive: true });
|
|
9830
9921
|
const cache = { version: CACHE_VERSION, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
|
|
9831
9922
|
await writeFile8(path, JSON.stringify(cache, null, 2), "utf8");
|
|
9832
9923
|
} catch {
|
|
@@ -10261,6 +10352,10 @@ var InternalSession = class {
|
|
|
10261
10352
|
onWarning: (msg) => {
|
|
10262
10353
|
this.emit({ type: "warning", message: msg });
|
|
10263
10354
|
},
|
|
10355
|
+
onGuardrail: (ev) => {
|
|
10356
|
+
this.emit({ type: "warning", message: ev.message });
|
|
10357
|
+
if (ev.kind === "limit_stopped") this.emit({ type: "status", status: "error" });
|
|
10358
|
+
},
|
|
10264
10359
|
askPermission: async (req) => {
|
|
10265
10360
|
if (mode === "auto") return "allow";
|
|
10266
10361
|
if (mode === "plan") {
|
|
@@ -10296,10 +10391,6 @@ var InternalSession = class {
|
|
|
10296
10391
|
});
|
|
10297
10392
|
return decision;
|
|
10298
10393
|
},
|
|
10299
|
-
onToolLimitReached: async () => {
|
|
10300
|
-
this.emit({ type: "status", status: "error" });
|
|
10301
|
-
return "stop";
|
|
10302
|
-
},
|
|
10303
10394
|
onKimiMdStale: () => {
|
|
10304
10395
|
this.onKimiMdStale?.();
|
|
10305
10396
|
}
|
|
@@ -10317,6 +10408,9 @@ var InternalSession = class {
|
|
|
10317
10408
|
hooks: this.hooks,
|
|
10318
10409
|
// M6.1: Stop fires at end-of-turn when enabled.
|
|
10319
10410
|
maxToolIterations,
|
|
10411
|
+
// SDK callers bound turns with `maxToolIterations`: stop cleanly at the
|
|
10412
|
+
// limit rather than resetting (never waits on a prompt either way).
|
|
10413
|
+
toolLimitBehavior: "stop",
|
|
10320
10414
|
reasoningEffort: this.reasoningEffort,
|
|
10321
10415
|
coauthor,
|
|
10322
10416
|
sessionId: this.sessionId,
|