@rallycry/conveyor-agent 7.2.18 → 7.2.19
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.
|
@@ -4915,8 +4915,34 @@ async function handleAskUserQuestion(host, input) {
|
|
|
4915
4915
|
}
|
|
4916
4916
|
return { behavior: "allow", updatedInput: { questions: input.questions, answers } };
|
|
4917
4917
|
}
|
|
4918
|
+
var EXPLORATION_TOOLS = /* @__PURE__ */ new Set(["Read", "Grep", "Glob"]);
|
|
4919
|
+
function trackExploration(tracker, toolName, input) {
|
|
4920
|
+
if (!EXPLORATION_TOOLS.has(toolName)) return null;
|
|
4921
|
+
if (toolName === "Read") {
|
|
4922
|
+
const filePath = String(input.file_path ?? "");
|
|
4923
|
+
if (filePath) return tracker.recordFileRead(filePath);
|
|
4924
|
+
}
|
|
4925
|
+
if (toolName === "Grep" || toolName === "Glob") {
|
|
4926
|
+
const pattern = String(input.pattern ?? "");
|
|
4927
|
+
if (pattern) return tracker.recordSearch(pattern);
|
|
4928
|
+
}
|
|
4929
|
+
return null;
|
|
4930
|
+
}
|
|
4918
4931
|
var DENIAL_WARNING_THRESHOLD = 3;
|
|
4919
4932
|
var DENIAL_FORCE_STOP_THRESHOLD = 8;
|
|
4933
|
+
function handleDenialEscalation(host, consecutiveDenials) {
|
|
4934
|
+
if (consecutiveDenials === DENIAL_WARNING_THRESHOLD) {
|
|
4935
|
+
host.connection.postChatMessage(
|
|
4936
|
+
`\u26A0\uFE0F Multiple tool denials detected. You are in ${host.agentMode} mode \u2014 file writes outside .claude/plans/ are not permitted. Focus on creating a plan instead of implementing code changes.`
|
|
4937
|
+
);
|
|
4938
|
+
}
|
|
4939
|
+
if (consecutiveDenials >= DENIAL_FORCE_STOP_THRESHOLD) {
|
|
4940
|
+
host.connection.postChatMessage(
|
|
4941
|
+
`Agent force-stopped after ${DENIAL_FORCE_STOP_THRESHOLD} consecutive tool denials. The agent appears stuck \u2014 send a message to resume.`
|
|
4942
|
+
);
|
|
4943
|
+
host.requestStop();
|
|
4944
|
+
}
|
|
4945
|
+
}
|
|
4920
4946
|
function resolveToolAccess(host, toolName, input) {
|
|
4921
4947
|
switch (host.agentMode) {
|
|
4922
4948
|
case "discovery":
|
|
@@ -4947,19 +4973,15 @@ function buildCanUseTool(host) {
|
|
|
4947
4973
|
return await handleAskUserQuestion(host, input);
|
|
4948
4974
|
}
|
|
4949
4975
|
const result = resolveToolAccess(host, toolName, input);
|
|
4976
|
+
if (result.behavior === "allow" && host.explorationTracker && !host.hasExitedPlanMode) {
|
|
4977
|
+
const signal = trackExploration(host.explorationTracker, toolName, input);
|
|
4978
|
+
if (signal) {
|
|
4979
|
+
host.connection.postChatMessage(signal.message);
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4950
4982
|
if (result.behavior === "deny") {
|
|
4951
4983
|
consecutiveDenials++;
|
|
4952
|
-
|
|
4953
|
-
host.connection.postChatMessage(
|
|
4954
|
-
`\u26A0\uFE0F Multiple tool denials detected. You are in ${host.agentMode} mode \u2014 file writes outside .claude/plans/ are not permitted. Focus on creating a plan instead of implementing code changes.`
|
|
4955
|
-
);
|
|
4956
|
-
}
|
|
4957
|
-
if (consecutiveDenials >= DENIAL_FORCE_STOP_THRESHOLD) {
|
|
4958
|
-
host.connection.postChatMessage(
|
|
4959
|
-
`Agent force-stopped after ${DENIAL_FORCE_STOP_THRESHOLD} consecutive tool denials. The agent appears stuck \u2014 send a message to resume.`
|
|
4960
|
-
);
|
|
4961
|
-
host.requestStop();
|
|
4962
|
-
}
|
|
4984
|
+
handleDenialEscalation(host, consecutiveDenials);
|
|
4963
4985
|
} else {
|
|
4964
4986
|
consecutiveDenials = 0;
|
|
4965
4987
|
}
|
|
@@ -5383,6 +5405,108 @@ var CostTracker = class {
|
|
|
5383
5405
|
}
|
|
5384
5406
|
};
|
|
5385
5407
|
|
|
5408
|
+
// src/execution/exploration-tracker.ts
|
|
5409
|
+
var FILE_REREAD_NUDGE_L1 = 3;
|
|
5410
|
+
var FILE_REREAD_NUDGE_L2 = 5;
|
|
5411
|
+
var SEARCH_REPEAT_NUDGE_L1 = 3;
|
|
5412
|
+
var SEARCH_REPEAT_NUDGE_L2 = 5;
|
|
5413
|
+
var RATIO_MIN_READS_L1 = 10;
|
|
5414
|
+
var RATIO_THRESHOLD_L1 = 0.4;
|
|
5415
|
+
var RATIO_MIN_READS_L2 = 15;
|
|
5416
|
+
var RATIO_THRESHOLD_L2 = 0.3;
|
|
5417
|
+
function normalizePath(filePath) {
|
|
5418
|
+
let normalized = filePath.replace(/^\.\//, "");
|
|
5419
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
5420
|
+
return normalized;
|
|
5421
|
+
}
|
|
5422
|
+
var ExplorationTracker = class {
|
|
5423
|
+
fileReadCounts = /* @__PURE__ */ new Map();
|
|
5424
|
+
searchCounts = /* @__PURE__ */ new Map();
|
|
5425
|
+
totalReads = 0;
|
|
5426
|
+
highestNudgeEmitted = 0;
|
|
5427
|
+
complexityMultiplier;
|
|
5428
|
+
constructor(isParentTask) {
|
|
5429
|
+
this.complexityMultiplier = isParentTask ? 1.5 : 1;
|
|
5430
|
+
}
|
|
5431
|
+
/** Record a file read and return a staleness signal if thresholds are crossed. */
|
|
5432
|
+
recordFileRead(filePath) {
|
|
5433
|
+
const normalized = normalizePath(filePath);
|
|
5434
|
+
const count = (this.fileReadCounts.get(normalized) ?? 0) + 1;
|
|
5435
|
+
this.fileReadCounts.set(normalized, count);
|
|
5436
|
+
this.totalReads++;
|
|
5437
|
+
return this.checkFileRereadSignal(normalized, count) ?? this.checkExplorationRatio();
|
|
5438
|
+
}
|
|
5439
|
+
/** Record a search pattern and return a staleness signal if thresholds are crossed. */
|
|
5440
|
+
recordSearch(pattern) {
|
|
5441
|
+
const count = (this.searchCounts.get(pattern) ?? 0) + 1;
|
|
5442
|
+
this.searchCounts.set(pattern, count);
|
|
5443
|
+
return this.checkSearchRepeatSignal(pattern, count);
|
|
5444
|
+
}
|
|
5445
|
+
scaledThreshold(base) {
|
|
5446
|
+
return Math.ceil(base * this.complexityMultiplier);
|
|
5447
|
+
}
|
|
5448
|
+
checkFileRereadSignal(filePath, count) {
|
|
5449
|
+
const l2 = this.scaledThreshold(FILE_REREAD_NUDGE_L2);
|
|
5450
|
+
const l1 = this.scaledThreshold(FILE_REREAD_NUDGE_L1);
|
|
5451
|
+
if (count >= l2 && this.highestNudgeEmitted < 2) {
|
|
5452
|
+
this.highestNudgeEmitted = 2;
|
|
5453
|
+
return {
|
|
5454
|
+
level: 2,
|
|
5455
|
+
message: `\u26A0\uFE0F Exploration warning: You've read "${filePath}" ${count} times, suggesting analysis paralysis. Write your plan with the context you have and call ExitPlanMode. If something specific is blocking you, describe the blocker in your plan.`
|
|
5456
|
+
};
|
|
5457
|
+
}
|
|
5458
|
+
if (count >= l1 && this.highestNudgeEmitted < 1) {
|
|
5459
|
+
this.highestNudgeEmitted = 1;
|
|
5460
|
+
return {
|
|
5461
|
+
level: 1,
|
|
5462
|
+
message: `Exploration note: You've read "${filePath}" ${count} times. Consider whether you have enough context to start writing your plan. If you're still exploring, try looking at different files.`
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
return null;
|
|
5466
|
+
}
|
|
5467
|
+
checkSearchRepeatSignal(pattern, count) {
|
|
5468
|
+
const l2 = this.scaledThreshold(SEARCH_REPEAT_NUDGE_L2);
|
|
5469
|
+
const l1 = this.scaledThreshold(SEARCH_REPEAT_NUDGE_L1);
|
|
5470
|
+
const displayPattern = pattern.length > 60 ? pattern.slice(0, 57) + "..." : pattern;
|
|
5471
|
+
if (count >= l2 && this.highestNudgeEmitted < 2) {
|
|
5472
|
+
this.highestNudgeEmitted = 2;
|
|
5473
|
+
return {
|
|
5474
|
+
level: 2,
|
|
5475
|
+
message: `\u26A0\uFE0F Exploration warning: You've searched for "${displayPattern}" ${count} times. Repeated searches for the same pattern suggest you may be stuck. Proceed with the information you have.`
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
if (count >= l1 && this.highestNudgeEmitted < 1) {
|
|
5479
|
+
this.highestNudgeEmitted = 1;
|
|
5480
|
+
return {
|
|
5481
|
+
level: 1,
|
|
5482
|
+
message: `Exploration note: You've searched for "${displayPattern}" ${count} times. If you're not finding what you need, try a different approach or broader pattern.`
|
|
5483
|
+
};
|
|
5484
|
+
}
|
|
5485
|
+
return null;
|
|
5486
|
+
}
|
|
5487
|
+
checkExplorationRatio() {
|
|
5488
|
+
const uniqueReads = this.fileReadCounts.size;
|
|
5489
|
+
const ratio = this.totalReads > 0 ? uniqueReads / this.totalReads : 1;
|
|
5490
|
+
const minReadsL2 = this.scaledThreshold(RATIO_MIN_READS_L2);
|
|
5491
|
+
if (this.totalReads >= minReadsL2 && ratio < RATIO_THRESHOLD_L2 && this.highestNudgeEmitted < 2) {
|
|
5492
|
+
this.highestNudgeEmitted = 2;
|
|
5493
|
+
return {
|
|
5494
|
+
level: 2,
|
|
5495
|
+
message: `\u26A0\uFE0F Exploration warning: Only ${Math.round(ratio * 100)}% of your ${this.totalReads} file reads are unique. This indicates significant re-reading. Write your plan with the context you have.`
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
const minReadsL1 = this.scaledThreshold(RATIO_MIN_READS_L1);
|
|
5499
|
+
if (this.totalReads >= minReadsL1 && ratio < RATIO_THRESHOLD_L1 && this.highestNudgeEmitted < 1) {
|
|
5500
|
+
this.highestNudgeEmitted = 1;
|
|
5501
|
+
return {
|
|
5502
|
+
level: 1,
|
|
5503
|
+
message: `Exploration note: ${Math.round(ratio * 100)}% of your ${this.totalReads} file reads are unique. You're re-reading files more than exploring new ones. Consider starting your plan.`
|
|
5504
|
+
};
|
|
5505
|
+
}
|
|
5506
|
+
return null;
|
|
5507
|
+
}
|
|
5508
|
+
};
|
|
5509
|
+
|
|
5386
5510
|
// src/runner/query-bridge.ts
|
|
5387
5511
|
var logger3 = createServiceLogger("QueryBridge");
|
|
5388
5512
|
var QueryBridge = class {
|
|
@@ -5474,6 +5598,7 @@ var QueryBridge = class {
|
|
|
5474
5598
|
harness: this.harness,
|
|
5475
5599
|
setupLog: [],
|
|
5476
5600
|
costTracker: this.costTracker,
|
|
5601
|
+
explorationTracker: bridge.mode.effectiveMode === "discovery" || bridge.mode.effectiveMode === "auto" && !bridge.mode.hasExitedPlanMode ? new ExplorationTracker(bridge._isParentTask) : null,
|
|
5477
5602
|
sessionIds: this.sessionIds,
|
|
5478
5603
|
pendingToolOutputs: this.pendingToolOutputs,
|
|
5479
5604
|
// Live getters/setters delegating to ModeController + bridge state
|
|
@@ -7671,4 +7796,4 @@ export {
|
|
|
7671
7796
|
loadForwardPorts,
|
|
7672
7797
|
loadConveyorConfig
|
|
7673
7798
|
};
|
|
7674
|
-
//# sourceMappingURL=chunk-
|
|
7799
|
+
//# sourceMappingURL=chunk-5MTPAVNZ.js.map
|