fix(runner): fix fingerprint collision on projectId and relax loop-break limits
This commit is contained in:
46
vibn-agent-runner/dist/agent-session-runner.js
vendored
46
vibn-agent-runner/dist/agent-session-runner.js
vendored
@@ -300,21 +300,30 @@ File: "${path.relative(opts.repoRoot ?? ctx.workspaceRoot, task.filePath)}" (lin
|
|||||||
const toolFingerprints = [];
|
const toolFingerprints = [];
|
||||||
let ralphIteration = 0;
|
let ralphIteration = 0;
|
||||||
function fingerprintToolCall(tc) {
|
function fingerprintToolCall(tc) {
|
||||||
if (tc.name === "shell_exec") {
|
const name = tc.name;
|
||||||
const cmd = String(tc.args?.command ?? "").trim();
|
const args = tc.args ?? {};
|
||||||
const verb = cmd
|
if (name === "shell_exec") {
|
||||||
.split("&&")
|
const cmd = String(args.command ?? "").trim();
|
||||||
.map((s) => s.trim())
|
const firstWord = cmd.split(/\s+/)[0] ?? "shell";
|
||||||
.find((s) => !s.startsWith("cd "))
|
return `shell_exec:${firstWord}`;
|
||||||
?.split(/\s+/)[0] ?? "shell";
|
|
||||||
return `shell_exec:${verb}`;
|
|
||||||
}
|
}
|
||||||
if (tc.name === "fs_write" ||
|
// Determine target based on most common descriptive parameter keys
|
||||||
tc.name === "fs_edit" ||
|
const target = args.path ??
|
||||||
tc.name === "fs_read") {
|
args.pattern ??
|
||||||
return `${tc.name}:${tc.args?.path}`;
|
args.command ??
|
||||||
|
args.commandId ??
|
||||||
|
args.appUuid ??
|
||||||
|
args.uuid ??
|
||||||
|
"";
|
||||||
|
if (target) {
|
||||||
|
return `${name}:${target}`;
|
||||||
}
|
}
|
||||||
return `${tc.name}:${Object.values(tc.args ?? {})[0]}`;
|
// Filter out common metadata like projectId, and use first real argument
|
||||||
|
const keys = Object.keys(args).filter((k) => k !== "projectId");
|
||||||
|
if (keys.length > 0) {
|
||||||
|
return `${name}:${args[keys[0]]}`;
|
||||||
|
}
|
||||||
|
return `${name}:default`;
|
||||||
}
|
}
|
||||||
while (subTurn < SUB_MAX_TURNS) {
|
while (subTurn < SUB_MAX_TURNS) {
|
||||||
if (opts.isStopped()) {
|
if (opts.isStopped()) {
|
||||||
@@ -421,20 +430,23 @@ ${verification.error}
|
|||||||
for (const tc of resp.toolCalls) {
|
for (const tc of resp.toolCalls) {
|
||||||
toolFingerprints.push(fingerprintToolCall(tc));
|
toolFingerprints.push(fingerprintToolCall(tc));
|
||||||
}
|
}
|
||||||
const window = toolFingerprints.slice(-6);
|
const window = toolFingerprints.slice(-12);
|
||||||
const counts = new Map();
|
const counts = new Map();
|
||||||
for (const fp of window)
|
for (const fp of window)
|
||||||
counts.set(fp, (counts.get(fp) ?? 0) + 1);
|
counts.set(fp, (counts.get(fp) ?? 0) + 1);
|
||||||
let maxRepeats = 0;
|
let maxRepeats = 0;
|
||||||
|
let repeatedCmd = "";
|
||||||
for (const [fp, n] of counts.entries()) {
|
for (const [fp, n] of counts.entries()) {
|
||||||
if (n > maxRepeats)
|
if (n > maxRepeats) {
|
||||||
maxRepeats = n;
|
maxRepeats = n;
|
||||||
|
repeatedCmd = fp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (maxRepeats >= 4) {
|
if (maxRepeats >= 6) {
|
||||||
await emit({
|
await emit({
|
||||||
ts: now(),
|
ts: now(),
|
||||||
type: "error",
|
type: "error",
|
||||||
text: `Loop detected in subtask execution, breaking loop.`,
|
text: `Loop detected in subtask execution (repeated "${repeatedCmd}" ${maxRepeats}x in last 12 calls), breaking loop.`,
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,24 +403,35 @@ File: "${path.relative(opts.repoRoot ?? ctx.workspaceRoot, task.filePath)}" (lin
|
|||||||
let ralphIteration = 0;
|
let ralphIteration = 0;
|
||||||
|
|
||||||
function fingerprintToolCall(tc: any) {
|
function fingerprintToolCall(tc: any) {
|
||||||
if (tc.name === "shell_exec") {
|
const name = tc.name;
|
||||||
const cmd = String(tc.args?.command ?? "").trim();
|
const args = tc.args ?? {};
|
||||||
const verb =
|
|
||||||
cmd
|
if (name === "shell_exec") {
|
||||||
.split("&&")
|
const cmd = String(args.command ?? "").trim();
|
||||||
.map((s) => s.trim())
|
const firstWord = cmd.split(/\s+/)[0] ?? "shell";
|
||||||
.find((s) => !s.startsWith("cd "))
|
return `shell_exec:${firstWord}`;
|
||||||
?.split(/\s+/)[0] ?? "shell";
|
|
||||||
return `shell_exec:${verb}`;
|
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
tc.name === "fs_write" ||
|
// Determine target based on most common descriptive parameter keys
|
||||||
tc.name === "fs_edit" ||
|
const target =
|
||||||
tc.name === "fs_read"
|
args.path ??
|
||||||
) {
|
args.pattern ??
|
||||||
return `${tc.name}:${tc.args?.path}`;
|
args.command ??
|
||||||
|
args.commandId ??
|
||||||
|
args.appUuid ??
|
||||||
|
args.uuid ??
|
||||||
|
"";
|
||||||
|
if (target) {
|
||||||
|
return `${name}:${target}`;
|
||||||
}
|
}
|
||||||
return `${tc.name}:${Object.values(tc.args ?? {})[0]}`;
|
|
||||||
|
// Filter out common metadata like projectId, and use first real argument
|
||||||
|
const keys = Object.keys(args).filter((k) => k !== "projectId");
|
||||||
|
if (keys.length > 0) {
|
||||||
|
return `${name}:${args[keys[0]]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${name}:default`;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (subTurn < SUB_MAX_TURNS) {
|
while (subTurn < SUB_MAX_TURNS) {
|
||||||
@@ -536,20 +547,24 @@ ${verification.error}
|
|||||||
for (const tc of resp.toolCalls) {
|
for (const tc of resp.toolCalls) {
|
||||||
toolFingerprints.push(fingerprintToolCall(tc));
|
toolFingerprints.push(fingerprintToolCall(tc));
|
||||||
}
|
}
|
||||||
const window = toolFingerprints.slice(-6);
|
const window = toolFingerprints.slice(-12);
|
||||||
const counts = new Map<string, number>();
|
const counts = new Map<string, number>();
|
||||||
for (const fp of window) counts.set(fp, (counts.get(fp) ?? 0) + 1);
|
for (const fp of window) counts.set(fp, (counts.get(fp) ?? 0) + 1);
|
||||||
|
|
||||||
let maxRepeats = 0;
|
let maxRepeats = 0;
|
||||||
|
let repeatedCmd = "";
|
||||||
for (const [fp, n] of counts.entries()) {
|
for (const [fp, n] of counts.entries()) {
|
||||||
if (n > maxRepeats) maxRepeats = n;
|
if (n > maxRepeats) {
|
||||||
|
maxRepeats = n;
|
||||||
|
repeatedCmd = fp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxRepeats >= 4) {
|
if (maxRepeats >= 6) {
|
||||||
await emit({
|
await emit({
|
||||||
ts: now(),
|
ts: now(),
|
||||||
type: "error",
|
type: "error",
|
||||||
text: `Loop detected in subtask execution, breaking loop.`,
|
text: `Loop detected in subtask execution (repeated "${repeatedCmd}" ${maxRepeats}x in last 12 calls), breaking loop.`,
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user