cc-claw 0.12.7 → 0.12.8
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/cli.js +87 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -72,7 +72,7 @@ var VERSION;
|
|
|
72
72
|
var init_version = __esm({
|
|
73
73
|
"src/version.ts"() {
|
|
74
74
|
"use strict";
|
|
75
|
-
VERSION = true ? "0.12.
|
|
75
|
+
VERSION = true ? "0.12.8" : (() => {
|
|
76
76
|
try {
|
|
77
77
|
return JSON.parse(readFileSync(join2(process.cwd(), "package.json"), "utf-8")).version ?? "unknown";
|
|
78
78
|
} catch {
|
|
@@ -4247,6 +4247,78 @@ var init_backends = __esm({
|
|
|
4247
4247
|
}
|
|
4248
4248
|
});
|
|
4249
4249
|
|
|
4250
|
+
// src/tool-loop-detector.ts
|
|
4251
|
+
function djb2Hash(str) {
|
|
4252
|
+
let hash = 5381;
|
|
4253
|
+
for (let i = 0; i < str.length; i++) {
|
|
4254
|
+
hash = (hash << 5) + hash + str.charCodeAt(i) & 4294967295;
|
|
4255
|
+
}
|
|
4256
|
+
return hash.toString(36);
|
|
4257
|
+
}
|
|
4258
|
+
function extractKeyField(input) {
|
|
4259
|
+
const key = input.file_path ?? input.path ?? input.file ?? input.command ?? input.cmd ?? input.url ?? input.query ?? input.search_query ?? input.pattern ?? input.content;
|
|
4260
|
+
if (key !== void 0 && key !== null) {
|
|
4261
|
+
return String(key);
|
|
4262
|
+
}
|
|
4263
|
+
const sorted = Object.keys(input).sort();
|
|
4264
|
+
const parts = sorted.map((k) => `${k}:${JSON.stringify(input[k])}`);
|
|
4265
|
+
return parts.join("|");
|
|
4266
|
+
}
|
|
4267
|
+
function fingerprint(toolName, input) {
|
|
4268
|
+
const key = extractKeyField(input);
|
|
4269
|
+
return `${toolName}:${djb2Hash(key)}`;
|
|
4270
|
+
}
|
|
4271
|
+
var DEFAULT_WINDOW_SIZE, DEFAULT_THRESHOLD, HARD_TURN_CAP, ToolLoopDetector;
|
|
4272
|
+
var init_tool_loop_detector = __esm({
|
|
4273
|
+
"src/tool-loop-detector.ts"() {
|
|
4274
|
+
"use strict";
|
|
4275
|
+
DEFAULT_WINDOW_SIZE = 15;
|
|
4276
|
+
DEFAULT_THRESHOLD = 3;
|
|
4277
|
+
HARD_TURN_CAP = 200;
|
|
4278
|
+
ToolLoopDetector = class {
|
|
4279
|
+
windowSize;
|
|
4280
|
+
threshold;
|
|
4281
|
+
window = [];
|
|
4282
|
+
constructor(windowSize = DEFAULT_WINDOW_SIZE, threshold = DEFAULT_THRESHOLD) {
|
|
4283
|
+
this.windowSize = windowSize;
|
|
4284
|
+
this.threshold = threshold;
|
|
4285
|
+
}
|
|
4286
|
+
/**
|
|
4287
|
+
* Record a tool call and check for loops.
|
|
4288
|
+
*
|
|
4289
|
+
* @returns `{ isLoop: true, reason }` if the same fingerprint appears
|
|
4290
|
+
* `threshold` or more times in the sliding window.
|
|
4291
|
+
*/
|
|
4292
|
+
addCall(toolName, input) {
|
|
4293
|
+
const fp = fingerprint(toolName, input);
|
|
4294
|
+
this.window.push(fp);
|
|
4295
|
+
while (this.window.length > this.windowSize) {
|
|
4296
|
+
this.window.shift();
|
|
4297
|
+
}
|
|
4298
|
+
let count = 0;
|
|
4299
|
+
for (const entry of this.window) {
|
|
4300
|
+
if (entry === fp) count++;
|
|
4301
|
+
}
|
|
4302
|
+
if (count >= this.threshold) {
|
|
4303
|
+
return {
|
|
4304
|
+
isLoop: true,
|
|
4305
|
+
reason: `Tool "${toolName}" called ${count}\xD7 with same input in last ${this.window.length} calls`
|
|
4306
|
+
};
|
|
4307
|
+
}
|
|
4308
|
+
return { isLoop: false };
|
|
4309
|
+
}
|
|
4310
|
+
/** Number of calls tracked so far. */
|
|
4311
|
+
get callCount() {
|
|
4312
|
+
return this.window.length;
|
|
4313
|
+
}
|
|
4314
|
+
/** Reset the detector (e.g., after a retry with a fresh session). */
|
|
4315
|
+
reset() {
|
|
4316
|
+
this.window.length = 0;
|
|
4317
|
+
}
|
|
4318
|
+
};
|
|
4319
|
+
}
|
|
4320
|
+
});
|
|
4321
|
+
|
|
4250
4322
|
// src/memory/inject.ts
|
|
4251
4323
|
function daysSince(dateStr) {
|
|
4252
4324
|
const date = /* @__PURE__ */ new Date(dateStr.replace(" ", "T") + (dateStr.includes("Z") ? "" : "Z"));
|
|
@@ -9170,6 +9242,7 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
9170
9242
|
let sawToolEvents = false;
|
|
9171
9243
|
let sawResultEvent = false;
|
|
9172
9244
|
let toolTurnCount = 0;
|
|
9245
|
+
const loopDetector = new ToolLoopDetector();
|
|
9173
9246
|
const t0 = Date.now();
|
|
9174
9247
|
const elapsed = () => `${((Date.now() - t0) / 1e3).toFixed(1)}s`;
|
|
9175
9248
|
const pendingTools = /* @__PURE__ */ new Map();
|
|
@@ -9215,10 +9288,19 @@ function spawnQuery(adapter, config2, model2, cancelState, thinkingLevel, timeou
|
|
|
9215
9288
|
error("[agent] tool action error:", err);
|
|
9216
9289
|
});
|
|
9217
9290
|
}
|
|
9218
|
-
if (
|
|
9291
|
+
if (adapter.id !== "claude") {
|
|
9219
9292
|
toolTurnCount++;
|
|
9220
|
-
if (
|
|
9221
|
-
|
|
9293
|
+
if (ev.toolName) {
|
|
9294
|
+
const check = loopDetector.addCall(ev.toolName, ev.toolInput ?? {});
|
|
9295
|
+
if (check.isLoop) {
|
|
9296
|
+
warn(`[agent] Loop detected for ${adapter.id}: ${check.reason} \u2014 stopping`);
|
|
9297
|
+
killProcessGroup(proc, "SIGTERM");
|
|
9298
|
+
}
|
|
9299
|
+
}
|
|
9300
|
+
const effectiveCap = maxTurns ?? HARD_TURN_CAP;
|
|
9301
|
+
if (toolTurnCount >= effectiveCap) {
|
|
9302
|
+
const label2 = maxTurns ? `Turn limit ${maxTurns}` : `Hard cap ${HARD_TURN_CAP}`;
|
|
9303
|
+
warn(`[agent] ${label2} reached for ${adapter.id} \u2014 stopping`);
|
|
9222
9304
|
killProcessGroup(proc, "SIGTERM");
|
|
9223
9305
|
}
|
|
9224
9306
|
}
|
|
@@ -9523,6 +9605,7 @@ var activeChats, chatLocks, SPAWN_TIMEOUT_MS, MCP_CONFIG_FLAG;
|
|
|
9523
9605
|
var init_agent = __esm({
|
|
9524
9606
|
"src/agent.ts"() {
|
|
9525
9607
|
"use strict";
|
|
9608
|
+
init_tool_loop_detector();
|
|
9526
9609
|
init_store5();
|
|
9527
9610
|
init_backends();
|
|
9528
9611
|
init_paths();
|
|
@@ -14571,7 +14654,6 @@ async function handleSideQuest(parentChatId, msg, channel) {
|
|
|
14571
14654
|
backend: backend2 ?? void 0,
|
|
14572
14655
|
settingsSourceChatId: parentChatId,
|
|
14573
14656
|
agentMode: "native",
|
|
14574
|
-
maxTurns: 10,
|
|
14575
14657
|
timeoutMs: 3e5,
|
|
14576
14658
|
bootstrapTier: "full"
|
|
14577
14659
|
});
|
package/package.json
CHANGED