kimiflare 0.50.1 → 0.51.0
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 +157 -90
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.js +75 -71
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2467,6 +2467,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2467
2467
|
let cumulativePromptTokens = 0;
|
|
2468
2468
|
let iter = 0;
|
|
2469
2469
|
let budgetExhausted = false;
|
|
2470
|
+
let loopExhausted = false;
|
|
2470
2471
|
while (true) {
|
|
2471
2472
|
if (budgetExhausted) {
|
|
2472
2473
|
opts2.messages.push({
|
|
@@ -2474,6 +2475,12 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2474
2475
|
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."
|
|
2475
2476
|
});
|
|
2476
2477
|
}
|
|
2478
|
+
if (loopExhausted) {
|
|
2479
|
+
opts2.messages.push({
|
|
2480
|
+
role: "system",
|
|
2481
|
+
content: "You have repeatedly called the same tools with identical arguments and are stuck in a loop. Please synthesize what you know from the conversation history and provide a final answer."
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2477
2484
|
if (iter >= max) {
|
|
2478
2485
|
if (opts2.callbacks.onToolLimitReached) {
|
|
2479
2486
|
const decision = await opts2.callbacks.onToolLimitReached();
|
|
@@ -2651,6 +2658,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2651
2658
|
logger.info("turn:complete", { sessionId: opts2.sessionId, durationMs: Math.round(performance.now() - turnStart) });
|
|
2652
2659
|
return;
|
|
2653
2660
|
}
|
|
2661
|
+
let blockedCount = 0;
|
|
2654
2662
|
for (const tc of toolCalls) {
|
|
2655
2663
|
if (opts2.signal.aborted) throw new DOMException("aborted", "AbortError");
|
|
2656
2664
|
const loopSignature = `${tc.function.name}:${stableStringify(tc.function.arguments)}`;
|
|
@@ -2673,6 +2681,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2673
2681
|
opts2.callbacks.onToolResult?.(loopResult);
|
|
2674
2682
|
recentToolCalls.push(loopSignature);
|
|
2675
2683
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
2684
|
+
blockedCount++;
|
|
2676
2685
|
continue;
|
|
2677
2686
|
}
|
|
2678
2687
|
if (tc.function.name === "web_fetch") {
|
|
@@ -2700,6 +2709,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2700
2709
|
opts2.callbacks.onToolResult?.(budgetResult);
|
|
2701
2710
|
recentToolCalls.push(loopSignature);
|
|
2702
2711
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
2712
|
+
blockedCount++;
|
|
2703
2713
|
continue;
|
|
2704
2714
|
}
|
|
2705
2715
|
if (domainCount >= WEB_FETCH_DOMAIN_THRESHOLD) {
|
|
@@ -2720,6 +2730,7 @@ Use console.log() to return results. Only console.log output will be sent back t
|
|
|
2720
2730
|
opts2.callbacks.onToolResult?.(loopResult);
|
|
2721
2731
|
recentToolCalls.push(loopSignature);
|
|
2722
2732
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
2733
|
+
blockedCount++;
|
|
2723
2734
|
continue;
|
|
2724
2735
|
}
|
|
2725
2736
|
webFetchHistory.push({ url, domain });
|
|
@@ -2855,6 +2866,9 @@ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
|
|
|
2855
2866
|
if (recentToolCalls.length > LOOP_WINDOW) recentToolCalls.shift();
|
|
2856
2867
|
}
|
|
2857
2868
|
}
|
|
2869
|
+
if (blockedCount === toolCalls.length && toolCalls.length > 0) {
|
|
2870
|
+
loopExhausted = true;
|
|
2871
|
+
}
|
|
2858
2872
|
if (opts2.sessionId) {
|
|
2859
2873
|
const current = driftAccumulator.get(opts2.sessionId) ?? 0;
|
|
2860
2874
|
if (current > 0) {
|
|
@@ -2883,6 +2897,9 @@ ${sandboxResult.output}` : `${warningPrefix}${sandboxResult.output}`;
|
|
|
2883
2897
|
if (budgetExhausted) {
|
|
2884
2898
|
throw new BudgetExhaustedError();
|
|
2885
2899
|
}
|
|
2900
|
+
if (loopExhausted) {
|
|
2901
|
+
throw new AgentLoopError();
|
|
2902
|
+
}
|
|
2886
2903
|
}
|
|
2887
2904
|
}
|
|
2888
2905
|
function validateToolArguments(raw) {
|
|
@@ -2894,7 +2911,7 @@ function validateToolArguments(raw) {
|
|
|
2894
2911
|
return "{}";
|
|
2895
2912
|
}
|
|
2896
2913
|
}
|
|
2897
|
-
var BudgetExhaustedError, codeModeApiCache, driftAccumulator, DRIFT_THRESHOLD, MAX_PROMPT_TOKENS, MAX_TOOL_CONTENT_CHARS;
|
|
2914
|
+
var BudgetExhaustedError, AgentLoopError, codeModeApiCache, driftAccumulator, DRIFT_THRESHOLD, MAX_PROMPT_TOKENS, MAX_TOOL_CONTENT_CHARS;
|
|
2898
2915
|
var init_loop = __esm({
|
|
2899
2916
|
"src/agent/loop.ts"() {
|
|
2900
2917
|
"use strict";
|
|
@@ -2913,6 +2930,12 @@ var init_loop = __esm({
|
|
|
2913
2930
|
this.name = "BudgetExhaustedError";
|
|
2914
2931
|
}
|
|
2915
2932
|
};
|
|
2933
|
+
AgentLoopError = class extends Error {
|
|
2934
|
+
constructor(message2 = "Agent got stuck repeating the same tool calls") {
|
|
2935
|
+
super(message2);
|
|
2936
|
+
this.name = "AgentLoopError";
|
|
2937
|
+
}
|
|
2938
|
+
};
|
|
2916
2939
|
codeModeApiCache = /* @__PURE__ */ new Map();
|
|
2917
2940
|
driftAccumulator = /* @__PURE__ */ new Map();
|
|
2918
2941
|
DRIFT_THRESHOLD = 5;
|
|
@@ -2953,88 +2976,47 @@ function isBlockedInPlanMode(toolName) {
|
|
|
2953
2976
|
if (toolName === "browser_fetch") return true;
|
|
2954
2977
|
return false;
|
|
2955
2978
|
}
|
|
2956
|
-
function
|
|
2957
|
-
const
|
|
2958
|
-
let
|
|
2959
|
-
let
|
|
2960
|
-
for (const ch of
|
|
2961
|
-
if (
|
|
2962
|
-
if (ch ===
|
|
2963
|
-
|
|
2964
|
-
} else {
|
|
2965
|
-
current += ch;
|
|
2966
|
-
}
|
|
2979
|
+
function getTokens(s) {
|
|
2980
|
+
const toks = [];
|
|
2981
|
+
let cur = "";
|
|
2982
|
+
let q = null;
|
|
2983
|
+
for (const ch of s) {
|
|
2984
|
+
if (q) {
|
|
2985
|
+
if (ch === q) q = null;
|
|
2986
|
+
else cur += ch;
|
|
2967
2987
|
} else if (ch === '"' || ch === "'") {
|
|
2968
|
-
|
|
2988
|
+
q = ch;
|
|
2969
2989
|
} else if (/\s/.test(ch)) {
|
|
2970
|
-
if (
|
|
2971
|
-
|
|
2972
|
-
|
|
2990
|
+
if (cur) {
|
|
2991
|
+
toks.push(cur);
|
|
2992
|
+
cur = "";
|
|
2973
2993
|
}
|
|
2974
2994
|
} else {
|
|
2975
|
-
|
|
2995
|
+
cur += ch;
|
|
2976
2996
|
}
|
|
2977
2997
|
}
|
|
2978
|
-
if (
|
|
2979
|
-
return
|
|
2998
|
+
if (cur) toks.push(cur);
|
|
2999
|
+
return toks;
|
|
2980
3000
|
}
|
|
2981
|
-
function
|
|
2982
|
-
const
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
for (let i = 0; i < command.length; i++) {
|
|
2986
|
-
const ch = command[i];
|
|
2987
|
-
if (inQuote) {
|
|
2988
|
-
if (ch === inQuote) {
|
|
2989
|
-
inQuote = null;
|
|
2990
|
-
}
|
|
2991
|
-
current += ch;
|
|
2992
|
-
continue;
|
|
2993
|
-
}
|
|
2994
|
-
if (ch === '"' || ch === "'") {
|
|
2995
|
-
inQuote = ch;
|
|
2996
|
-
current += ch;
|
|
2997
|
-
continue;
|
|
2998
|
-
}
|
|
2999
|
-
let matchedOp = false;
|
|
3000
|
-
for (const op of operators) {
|
|
3001
|
-
if (command.slice(i, i + op.length) === op) {
|
|
3002
|
-
segments.push(current.trim());
|
|
3003
|
-
current = "";
|
|
3004
|
-
i += op.length - 1;
|
|
3005
|
-
matchedOp = true;
|
|
3006
|
-
break;
|
|
3007
|
-
}
|
|
3008
|
-
}
|
|
3009
|
-
if (matchedOp) continue;
|
|
3010
|
-
current += ch;
|
|
3011
|
-
}
|
|
3012
|
-
if (current.trim()) segments.push(current.trim());
|
|
3013
|
-
return segments;
|
|
3014
|
-
}
|
|
3015
|
-
function isReadOnlyBashSegment(command) {
|
|
3016
|
-
const trimmed = command.trim();
|
|
3017
|
-
if (!trimmed) return false;
|
|
3018
|
-
const tokens = tokenizeCommand(trimmed);
|
|
3019
|
-
if (tokens.length === 0) return false;
|
|
3020
|
-
const cmd = tokens[0];
|
|
3021
|
-
const args = tokens.slice(1);
|
|
3001
|
+
function isReadOnlySegment(seg) {
|
|
3002
|
+
const toks = getTokens(seg.trim());
|
|
3003
|
+
if (toks.length === 0) return false;
|
|
3004
|
+
const [cmd, sub, ...rest] = toks;
|
|
3022
3005
|
if (cmd === "git") {
|
|
3023
|
-
const
|
|
3024
|
-
const allowed = GIT_READONLY_SUBCOMMANDS[sub];
|
|
3006
|
+
const allowed = GIT_READONLY_SUBCOMMANDS[sub ?? ""];
|
|
3025
3007
|
if (allowed === void 0) return false;
|
|
3026
3008
|
if (allowed === true) return true;
|
|
3027
3009
|
switch (sub) {
|
|
3028
3010
|
case "branch":
|
|
3029
|
-
return !
|
|
3011
|
+
return !rest.some((a) => /^-[dDmMcC]/.test(a));
|
|
3030
3012
|
case "stash":
|
|
3031
|
-
return
|
|
3013
|
+
return rest[0] === "list";
|
|
3032
3014
|
case "remote":
|
|
3033
|
-
return
|
|
3015
|
+
return rest[0] === "-v" || rest[0] === "--verbose" || rest.length === 0;
|
|
3034
3016
|
case "tag":
|
|
3035
|
-
return
|
|
3017
|
+
return rest[0] === "-l" || rest[0] === "--list" || rest.length === 0;
|
|
3036
3018
|
case "config":
|
|
3037
|
-
return
|
|
3019
|
+
return rest[0] === "--list" || rest[0]?.startsWith("--get") === true || rest.length === 0;
|
|
3038
3020
|
default:
|
|
3039
3021
|
return false;
|
|
3040
3022
|
}
|
|
@@ -3045,10 +3027,32 @@ function isReadOnlyBash(command) {
|
|
|
3045
3027
|
const trimmed = command.trim();
|
|
3046
3028
|
if (!trimmed) return false;
|
|
3047
3029
|
if (DANGEROUS_PATTERNS.test(trimmed)) return false;
|
|
3048
|
-
const
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3030
|
+
const segs = [];
|
|
3031
|
+
let cur = "";
|
|
3032
|
+
let q = null;
|
|
3033
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
3034
|
+
const ch = trimmed[i];
|
|
3035
|
+
if (q) {
|
|
3036
|
+
if (ch === q) q = null;
|
|
3037
|
+
cur += ch;
|
|
3038
|
+
} else if (ch === '"' || ch === "'") {
|
|
3039
|
+
q = ch;
|
|
3040
|
+
cur += ch;
|
|
3041
|
+
} else if (trimmed.slice(i, i + 2) === "&&") {
|
|
3042
|
+
segs.push(cur);
|
|
3043
|
+
cur = "";
|
|
3044
|
+
i++;
|
|
3045
|
+
} else if (ch === "|") {
|
|
3046
|
+
segs.push(cur);
|
|
3047
|
+
cur = "";
|
|
3048
|
+
} else {
|
|
3049
|
+
cur += ch;
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
if (cur.trim()) segs.push(cur);
|
|
3053
|
+
if (segs.length === 0) return false;
|
|
3054
|
+
for (const seg of segs) {
|
|
3055
|
+
if (!isReadOnlySegment(seg.trim())) return false;
|
|
3052
3056
|
}
|
|
3053
3057
|
return true;
|
|
3054
3058
|
}
|
|
@@ -6078,13 +6082,18 @@ __export(auth_exports, {
|
|
|
6078
6082
|
registerDevice: () => registerDevice,
|
|
6079
6083
|
saveCloudCredentials: () => saveCloudCredentials
|
|
6080
6084
|
});
|
|
6081
|
-
import { readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
6082
|
-
import {
|
|
6085
|
+
import { readFile as readFile11, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
6086
|
+
import { createHash } from "crypto";
|
|
6087
|
+
import { homedir as homedir9, hostname, userInfo } from "os";
|
|
6083
6088
|
import { join as join15 } from "path";
|
|
6084
6089
|
function cloudCredPath() {
|
|
6085
6090
|
const xdg = process.env.XDG_CONFIG_HOME || join15(homedir9(), ".config");
|
|
6086
6091
|
return join15(xdg, "kimiflare", "cloud.json");
|
|
6087
6092
|
}
|
|
6093
|
+
function deviceIdPath() {
|
|
6094
|
+
const xdg = process.env.XDG_DATA_HOME || join15(homedir9(), ".local", "share");
|
|
6095
|
+
return join15(xdg, "kimiflare", "device_id");
|
|
6096
|
+
}
|
|
6088
6097
|
function generateCode() {
|
|
6089
6098
|
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
6090
6099
|
let out = "";
|
|
@@ -6093,16 +6102,51 @@ function generateCode() {
|
|
|
6093
6102
|
}
|
|
6094
6103
|
return out;
|
|
6095
6104
|
}
|
|
6096
|
-
function
|
|
6105
|
+
function deriveStableDeviceId() {
|
|
6106
|
+
const seed = `${hostname()}:${userInfo().username}:${homedir9()}`;
|
|
6107
|
+
const hash = createHash("sha256").update(seed).digest();
|
|
6108
|
+
return hash.subarray(0, 16).toString("hex");
|
|
6109
|
+
}
|
|
6110
|
+
function generateRandomDeviceId() {
|
|
6097
6111
|
const arr = new Uint8Array(16);
|
|
6098
6112
|
crypto.getRandomValues(arr);
|
|
6099
6113
|
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
6100
6114
|
}
|
|
6101
|
-
function
|
|
6115
|
+
async function getOrCreateDeviceId() {
|
|
6116
|
+
try {
|
|
6117
|
+
const raw = await readFile11(deviceIdPath(), "utf8");
|
|
6118
|
+
const id = raw.trim();
|
|
6119
|
+
if (/^[0-9a-f]{32}$/i.test(id)) return id;
|
|
6120
|
+
} catch {
|
|
6121
|
+
}
|
|
6122
|
+
try {
|
|
6123
|
+
const raw = await readFile11(cloudCredPath(), "utf8");
|
|
6124
|
+
const parsed = JSON.parse(raw);
|
|
6125
|
+
if (parsed.deviceId && /^[0-9a-f]{32}$/i.test(parsed.deviceId)) {
|
|
6126
|
+
await persistDeviceId(parsed.deviceId);
|
|
6127
|
+
return parsed.deviceId;
|
|
6128
|
+
}
|
|
6129
|
+
} catch {
|
|
6130
|
+
}
|
|
6131
|
+
let deviceId;
|
|
6132
|
+
try {
|
|
6133
|
+
deviceId = deriveStableDeviceId();
|
|
6134
|
+
} catch {
|
|
6135
|
+
deviceId = generateRandomDeviceId();
|
|
6136
|
+
}
|
|
6137
|
+
await persistDeviceId(deviceId);
|
|
6138
|
+
return deviceId;
|
|
6139
|
+
}
|
|
6140
|
+
async function persistDeviceId(deviceId) {
|
|
6141
|
+
const p = deviceIdPath();
|
|
6142
|
+
await mkdir8(join15(p, ".."), { recursive: true });
|
|
6143
|
+
await writeFile8(p, deviceId, { mode: 384 });
|
|
6144
|
+
}
|
|
6145
|
+
async function generateDeviceCodes() {
|
|
6102
6146
|
const deviceCode = `device-${generateCode()}-${Date.now()}`;
|
|
6103
6147
|
const userCode = `${generateCode()}-${generateCode()}`;
|
|
6104
6148
|
const authUrl = `${CLOUD_API_URL}/auth?code=${encodeURIComponent(userCode)}`;
|
|
6105
|
-
const deviceId =
|
|
6149
|
+
const deviceId = await getOrCreateDeviceId();
|
|
6106
6150
|
return { deviceCode, userCode, authUrl, deviceId };
|
|
6107
6151
|
}
|
|
6108
6152
|
async function registerDevice(codes) {
|
|
@@ -6157,6 +6201,10 @@ async function loadCloudCredentials() {
|
|
|
6157
6201
|
const raw = await readFile11(cloudCredPath(), "utf8");
|
|
6158
6202
|
const parsed = JSON.parse(raw);
|
|
6159
6203
|
if (parsed.expiresAt && parsed.expiresAt > Date.now() / 1e3 && parsed.accessToken) {
|
|
6204
|
+
if (parsed.deviceId) {
|
|
6205
|
+
await persistDeviceId(parsed.deviceId).catch(() => {
|
|
6206
|
+
});
|
|
6207
|
+
}
|
|
6160
6208
|
return parsed;
|
|
6161
6209
|
}
|
|
6162
6210
|
} catch {
|
|
@@ -6166,6 +6214,10 @@ async function loadCloudCredentials() {
|
|
|
6166
6214
|
async function saveCloudCredentials(creds) {
|
|
6167
6215
|
const p = cloudCredPath();
|
|
6168
6216
|
await writeFile8(p, JSON.stringify(creds, null, 2), "utf8");
|
|
6217
|
+
if (creds.deviceId) {
|
|
6218
|
+
await persistDeviceId(creds.deviceId).catch(() => {
|
|
6219
|
+
});
|
|
6220
|
+
}
|
|
6169
6221
|
}
|
|
6170
6222
|
async function clearCloudCredentials() {
|
|
6171
6223
|
try {
|
|
@@ -6173,9 +6225,14 @@ async function clearCloudCredentials() {
|
|
|
6173
6225
|
await unlink5(cloudCredPath());
|
|
6174
6226
|
} catch {
|
|
6175
6227
|
}
|
|
6228
|
+
try {
|
|
6229
|
+
const { unlink: unlink5 } = await import("fs/promises");
|
|
6230
|
+
await unlink5(deviceIdPath());
|
|
6231
|
+
} catch {
|
|
6232
|
+
}
|
|
6176
6233
|
}
|
|
6177
6234
|
async function authenticateDevice(onStatus) {
|
|
6178
|
-
const codes = generateDeviceCodes();
|
|
6235
|
+
const codes = await generateDeviceCodes();
|
|
6179
6236
|
await registerDevice(codes);
|
|
6180
6237
|
onStatus({ url: codes.authUrl, userCode: codes.userCode, polling: false });
|
|
6181
6238
|
const startTime = Date.now();
|
|
@@ -8309,7 +8366,7 @@ __export(sessions_exports, {
|
|
|
8309
8366
|
saveSession: () => saveSession,
|
|
8310
8367
|
sessionsDir: () => sessionsDir2
|
|
8311
8368
|
});
|
|
8312
|
-
import { readFile as readFile12, writeFile as writeFile9, mkdir as
|
|
8369
|
+
import { readFile as readFile12, writeFile as writeFile9, mkdir as mkdir9, readdir as readdir3, stat as stat4 } from "fs/promises";
|
|
8313
8370
|
import { homedir as homedir10 } from "os";
|
|
8314
8371
|
import { join as join17 } from "path";
|
|
8315
8372
|
function sessionsDir2() {
|
|
@@ -8333,7 +8390,7 @@ function makeSessionId(firstPrompt) {
|
|
|
8333
8390
|
}
|
|
8334
8391
|
async function saveSession(file) {
|
|
8335
8392
|
const dir = sessionsDir2();
|
|
8336
|
-
await
|
|
8393
|
+
await mkdir9(dir, { recursive: true });
|
|
8337
8394
|
const path = join17(dir, `${file.id}.json`);
|
|
8338
8395
|
await writeFile9(path, JSON.stringify(file, null, 2), "utf8");
|
|
8339
8396
|
return path;
|
|
@@ -8443,7 +8500,7 @@ var init_pricing = __esm({
|
|
|
8443
8500
|
});
|
|
8444
8501
|
|
|
8445
8502
|
// src/usage-tracker.ts
|
|
8446
|
-
import { readFile as readFile13, writeFile as writeFile10, mkdir as
|
|
8503
|
+
import { readFile as readFile13, writeFile as writeFile10, mkdir as mkdir10 } from "fs/promises";
|
|
8447
8504
|
import { homedir as homedir11 } from "os";
|
|
8448
8505
|
import { join as join18 } from "path";
|
|
8449
8506
|
function usageDir2() {
|
|
@@ -8473,7 +8530,7 @@ async function loadLog2() {
|
|
|
8473
8530
|
return { version: LOG_VERSION2, days: [], sessions: [] };
|
|
8474
8531
|
}
|
|
8475
8532
|
async function saveLog(log2) {
|
|
8476
|
-
await
|
|
8533
|
+
await mkdir10(usageDir2(), { recursive: true });
|
|
8477
8534
|
await writeFile10(usagePath2(), JSON.stringify(log2, null, 2), "utf8");
|
|
8478
8535
|
}
|
|
8479
8536
|
async function loadHistory() {
|
|
@@ -8502,7 +8559,7 @@ async function upsertHistoryDay(day) {
|
|
|
8502
8559
|
entries.push(day);
|
|
8503
8560
|
}
|
|
8504
8561
|
const lines = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
8505
|
-
await
|
|
8562
|
+
await mkdir10(usageDir2(), { recursive: true });
|
|
8506
8563
|
await writeFile10(historyPath(), lines, "utf8");
|
|
8507
8564
|
}
|
|
8508
8565
|
function getOrCreateDay(log2, date) {
|
|
@@ -8973,7 +9030,7 @@ var init_session = __esm({
|
|
|
8973
9030
|
if (err.name === "AbortError") {
|
|
8974
9031
|
this.emit({ type: "session.end", reason: "aborted" });
|
|
8975
9032
|
this.emit({ type: "status", status: "idle" });
|
|
8976
|
-
} else if (err instanceof BudgetExhaustedError) {
|
|
9033
|
+
} else if (err instanceof BudgetExhaustedError || err instanceof AgentLoopError) {
|
|
8977
9034
|
this.emit({ type: "session.end", reason: "error", error: err.message });
|
|
8978
9035
|
this.emit({ type: "status", status: "error" });
|
|
8979
9036
|
throw err;
|
|
@@ -12027,7 +12084,7 @@ function Onboarding({ onDone, onCancel }) {
|
|
|
12027
12084
|
);
|
|
12028
12085
|
const startCloudAuth = useCallback(async () => {
|
|
12029
12086
|
try {
|
|
12030
|
-
const codes = generateDeviceCodes();
|
|
12087
|
+
const codes = await generateDeviceCodes();
|
|
12031
12088
|
await registerDevice(codes);
|
|
12032
12089
|
setCloudAuth({ phase: "ready", codes });
|
|
12033
12090
|
setStep("cloudAuth");
|
|
@@ -12892,7 +12949,7 @@ var init_skills = __esm({
|
|
|
12892
12949
|
});
|
|
12893
12950
|
|
|
12894
12951
|
// src/skills/manager.ts
|
|
12895
|
-
import { mkdir as
|
|
12952
|
+
import { mkdir as mkdir11, writeFile as writeFile11, unlink as unlink2, readFile as readFile15 } from "fs/promises";
|
|
12896
12953
|
import { join as join21 } from "path";
|
|
12897
12954
|
import matter2 from "gray-matter";
|
|
12898
12955
|
function getSkillDirs(cwd) {
|
|
@@ -12933,7 +12990,7 @@ ${yaml}
|
|
|
12933
12990
|
|
|
12934
12991
|
Add your instructions here.
|
|
12935
12992
|
`;
|
|
12936
|
-
await
|
|
12993
|
+
await mkdir11(dir, { recursive: true });
|
|
12937
12994
|
await writeFile11(filepath, content, "utf8");
|
|
12938
12995
|
return { filepath };
|
|
12939
12996
|
}
|
|
@@ -13015,7 +13072,7 @@ var init_image = __esm({
|
|
|
13015
13072
|
});
|
|
13016
13073
|
|
|
13017
13074
|
// src/util/state.ts
|
|
13018
|
-
import { readFile as readFile17, writeFile as writeFile12, mkdir as
|
|
13075
|
+
import { readFile as readFile17, writeFile as writeFile12, mkdir as mkdir12 } from "fs/promises";
|
|
13019
13076
|
import { homedir as homedir13 } from "os";
|
|
13020
13077
|
import { join as join22 } from "path";
|
|
13021
13078
|
function statePath() {
|
|
@@ -13032,7 +13089,7 @@ async function readState() {
|
|
|
13032
13089
|
}
|
|
13033
13090
|
async function writeState(state) {
|
|
13034
13091
|
const path = statePath();
|
|
13035
|
-
await
|
|
13092
|
+
await mkdir12(join22(path, ".."), { recursive: true });
|
|
13036
13093
|
await writeFile12(path, JSON.stringify(state, null, 2) + "\n", "utf8");
|
|
13037
13094
|
}
|
|
13038
13095
|
async function markCreatorMessageSeen(version) {
|
|
@@ -13490,7 +13547,7 @@ var init_builtins = __esm({
|
|
|
13490
13547
|
});
|
|
13491
13548
|
|
|
13492
13549
|
// src/commands/save.ts
|
|
13493
|
-
import { mkdir as
|
|
13550
|
+
import { mkdir as mkdir13, writeFile as writeFile13, unlink as unlink3 } from "fs/promises";
|
|
13494
13551
|
import { dirname as dirname10 } from "path";
|
|
13495
13552
|
async function saveCustomCommand(opts2) {
|
|
13496
13553
|
const dir = opts2.source === "project" ? projectCommandsDir(opts2.cwd) : globalCommandsDir();
|
|
@@ -13502,7 +13559,7 @@ async function saveCustomCommand(opts2) {
|
|
|
13502
13559
|
if (opts2.effort) data.effort = opts2.effort;
|
|
13503
13560
|
const frontmatter = serializeFrontmatter(data);
|
|
13504
13561
|
const content = frontmatter + opts2.template;
|
|
13505
|
-
await
|
|
13562
|
+
await mkdir13(dirname10(filepath), { recursive: true });
|
|
13506
13563
|
await writeFile13(filepath, content, "utf8");
|
|
13507
13564
|
return { filepath };
|
|
13508
13565
|
}
|
|
@@ -18044,6 +18101,11 @@ ${wcagWarnings.join("\n")}` }
|
|
|
18044
18101
|
...es,
|
|
18045
18102
|
{ kind: "cloud_quota_exhausted", key: mkKey(), used, limit, expiresAt }
|
|
18046
18103
|
]);
|
|
18104
|
+
} else if (e instanceof AgentLoopError) {
|
|
18105
|
+
setEvents((es) => [
|
|
18106
|
+
...es,
|
|
18107
|
+
{ kind: "error", key: mkKey(), text: "The agent got stuck repeating the same actions. Here's what we know so far." }
|
|
18108
|
+
]);
|
|
18047
18109
|
} else {
|
|
18048
18110
|
const displayText = e instanceof KimiApiError ? humanizeCloudflareError(e) : `init failed: ${e.message}`;
|
|
18049
18111
|
setEvents((es) => [
|
|
@@ -20434,6 +20496,11 @@ async function runPrintMode(opts2) {
|
|
|
20434
20496
|
process.exitCode = 42;
|
|
20435
20497
|
return;
|
|
20436
20498
|
}
|
|
20499
|
+
if (err instanceof AgentLoopError) {
|
|
20500
|
+
process.stderr.write("\n\x1B[33m[Agent loop detected \u2014 exiting with code 43]\x1B[0m\n");
|
|
20501
|
+
process.exitCode = 43;
|
|
20502
|
+
return;
|
|
20503
|
+
}
|
|
20437
20504
|
if (err instanceof KimiApiError) {
|
|
20438
20505
|
process.stderr.write(`
|
|
20439
20506
|
\x1B[31mError: ${humanizeCloudflareError(err)}\x1B[0m
|