fix: resolve CONFLICT error after interrupt during tool execution (#949)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
64
src/tests/cli/approval-recovery-wiring.test.ts
Normal file
64
src/tests/cli/approval-recovery-wiring.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
describe("approval recovery wiring", () => {
|
||||
test("pre-stream catch uses shared recovery router and stale input rebuild", () => {
|
||||
const appPath = fileURLToPath(
|
||||
new URL("../../cli/App.tsx", import.meta.url),
|
||||
);
|
||||
const source = readFileSync(appPath, "utf-8");
|
||||
|
||||
const start = source.indexOf("} catch (preStreamError) {");
|
||||
const end = source.indexOf(
|
||||
"// Check again after network call - user may have pressed Escape during sendMessageStream",
|
||||
);
|
||||
|
||||
expect(start).toBeGreaterThan(-1);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
|
||||
const segment = source.slice(start, end);
|
||||
|
||||
expect(segment).toContain("extractConflictDetail(preStreamError)");
|
||||
expect(segment).toContain("getPreStreamErrorAction(");
|
||||
expect(segment).toContain('preStreamAction === "resolve_approval_pending"');
|
||||
expect(segment).toContain("rebuildInputWithFreshDenials(");
|
||||
});
|
||||
|
||||
test("lazy recovery is not gated by hasApprovalInPayload", () => {
|
||||
const appPath = fileURLToPath(
|
||||
new URL("../../cli/App.tsx", import.meta.url),
|
||||
);
|
||||
const source = readFileSync(appPath, "utf-8");
|
||||
|
||||
const start = source.indexOf("const approvalPendingDetected =");
|
||||
const end = source.indexOf("// Check if this is a retriable error");
|
||||
|
||||
expect(start).toBeGreaterThan(-1);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
|
||||
const segment = source.slice(start, end);
|
||||
|
||||
expect(segment).toContain("approvalPendingDetected &&");
|
||||
expect(segment).not.toContain("!hasApprovalInPayload &&");
|
||||
});
|
||||
|
||||
test("tool interrupt branch includes backend cancel call before early return", () => {
|
||||
const appPath = fileURLToPath(
|
||||
new URL("../../cli/App.tsx", import.meta.url),
|
||||
);
|
||||
const source = readFileSync(appPath, "utf-8");
|
||||
|
||||
const start = source.indexOf("if (\n isExecutingTool");
|
||||
const end = source.indexOf("if (!streaming || interruptRequested)");
|
||||
|
||||
expect(start).toBeGreaterThan(-1);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
|
||||
const segment = source.slice(start, end);
|
||||
|
||||
expect(segment).toContain("getClient()");
|
||||
expect(segment).toContain("client.agents.messages.cancel");
|
||||
expect(segment).toContain("client.conversations.cancel");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user