feat(hooks): add json-error-recovery hook to prevent infinite retry loops

This commit is contained in:
bowtiedswan
2026-01-13 10:02:21 +02:00
parent 6208c07809
commit 86f2a93fc9
7 changed files with 121 additions and 0 deletions
@@ -0,0 +1,65 @@
import { beforeEach, describe, expect, it } from "bun:test"
import {
createJsonErrorRecoveryHook,
JSON_ERROR_PATTERNS,
JSON_ERROR_REMINDER,
} from "./index"
describe("createJsonErrorRecoveryHook", () => {
let hook: ReturnType<typeof createJsonErrorRecoveryHook>
beforeEach(() => {
hook = createJsonErrorRecoveryHook({} as any)
})
describe("tool.execute.after", () => {
const createInput = () => ({
tool: "Read",
sessionID: "test-session",
callID: "test-call-id",
})
const createOutput = (outputText: string) => ({
title: "Tool Error",
output: outputText,
metadata: {},
})
it("appends reminder when output includes JSON parse error", async () => {
const input = createInput()
const output = createOutput("JSON Parse error: Expected '}'")
await hook["tool.execute.after"](input, output)
expect(output.output).toContain(JSON_ERROR_REMINDER)
})
it("appends reminder when output includes SyntaxError", async () => {
const input = createInput()
const output = createOutput("SyntaxError: Unexpected token in JSON at position 10")
await hook["tool.execute.after"](input, output)
expect(output.output).toContain(JSON_ERROR_REMINDER)
})
it("does not append reminder for normal output", async () => {
const input = createInput()
const output = createOutput("Task completed successfully")
await hook["tool.execute.after"](input, output)
expect(output.output).toBe("Task completed successfully")
})
})
describe("JSON_ERROR_PATTERNS", () => {
it("contains known parse error patterns", () => {
expect(JSON_ERROR_PATTERNS).toContain("json parse error")
expect(JSON_ERROR_PATTERNS).toContain("syntaxerror: unexpected token")
expect(JSON_ERROR_PATTERNS).toContain("expected '}'")
expect(JSON_ERROR_PATTERNS).toContain("unexpected eof")
})
})
})