Skip to content

Commit fda9718

Browse files
committed
fix(agent): never name tool_search as the doom-loop example
1 parent f94f6c1 commit fda9718

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

‎src/agent/doom-loop-note.test.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,33 @@ test("the note offers an on-wire switch before the tool_search fallback", () =>
3939
expect(note).toMatch(/reply to the operator/i);
4040
});
4141

42+
test("the note skips tool_search when another remaining tool is on the wire", () => {
43+
const note = createDoomLoopCorrectiveNote(() => [
44+
"manage_tasks",
45+
"tool_search",
46+
"read_file",
47+
])(repeat);
48+
expect(note).toMatch(/already on the wire instead \(for example read_file\)/);
49+
expect(note).not.toMatch(/for example tool_search/);
50+
});
51+
52+
test("the note uses the fallback when only tool_search remains", () => {
53+
const note = createDoomLoopCorrectiveNote(() => [
54+
"manage_tasks",
55+
"tool_search",
56+
])(repeat);
57+
expect(note).not.toMatch(/for example tool_search/);
58+
expect(note).toContain("call tool_search to discover a different tool");
59+
expect(note).not.toMatch(/already on the wire instead/);
60+
});
61+
62+
test("the note uses the fallback when every advertised name is looped", () => {
63+
const note = createDoomLoopCorrectiveNote(() => ["manage_tasks"])(repeat);
64+
expect(note).not.toMatch(/for example /);
65+
expect(note).not.toMatch(/already on the wire instead/);
66+
expect(note).toContain("call tool_search to discover a different tool");
67+
});
68+
4269
test("the note reads the wire list lazily per invocation", () => {
4370
let wire: string[] = ["read_file"];
4471
const builder = createDoomLoopCorrectiveNote(() => wire);

‎src/agent/doom-loop-note.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ export function createDoomLoopCorrectiveNote(
2323
// Name one non-looped tool already on the wire as the first escape, so
2424
// the model switches instead of repeating. tool_search stays a fallback
2525
// rather than the example — it is named in the fallback sentence.
26-
const example =
27-
names.find((name) => !looped.has(name) && name !== "tool_search") ??
28-
names.find((name) => !looped.has(name));
26+
const example = names.find(
27+
(name) => !looped.has(name) && name !== "tool_search",
28+
);
2929
const escape =
3030
example === undefined
3131
? `Do not call this batch again — call tool_search to discover a ` +

0 commit comments

Comments
 (0)