mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
* fix: sanitize Read tool args to prevent retry loops from non-Anthropic models * fix: sanitize invalid Read pages from tool args Non-Anthropic models sometimes emit optional Read args like pages: "" for non-PDF files, which Claude Code rejects before the tool runs. Drop invalid pages values, keep valid PDF page ranges, and coerce numeric string bounds before clamping limit/offset. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
62 lines
2.0 KiB
JavaScript
62 lines
2.0 KiB
JavaScript
import { describe, expect, it } from "vitest";
|
|
import { openaiToClaudeResponse } from "../../open-sse/translator/response/openai-to-claude.js";
|
|
|
|
function createState() {
|
|
return { toolCalls: new Map(), nextBlockIndex: 0 };
|
|
}
|
|
|
|
function getInputJsonDelta(events) {
|
|
return events.find((event) => event.type === "content_block_delta" && event.delta?.type === "input_json_delta")?.delta.partial_json;
|
|
}
|
|
|
|
describe("openaiToClaudeResponse tool argument sanitization", () => {
|
|
it("drops invalid Read pages and clamps numeric bounds", () => {
|
|
const state = createState();
|
|
|
|
openaiToClaudeResponse({
|
|
id: "chatcmpl-test-read",
|
|
model: "test-model",
|
|
choices: [{ delta: { tool_calls: [{ index: 0, id: "toolu_read", function: { name: "Read" } }] } }],
|
|
}, state);
|
|
|
|
const events = openaiToClaudeResponse({
|
|
id: "chatcmpl-test-read",
|
|
model: "test-model",
|
|
choices: [{
|
|
delta: { tool_calls: [{ index: 0, function: { arguments: JSON.stringify({ file_path: "F:/repo/file.js", offset: -5, limit: 999999999, pages: "" }) } }] },
|
|
finish_reason: "tool_calls",
|
|
}],
|
|
}, state);
|
|
|
|
expect(JSON.parse(getInputJsonDelta(events))).toEqual({
|
|
file_path: "F:/repo/file.js",
|
|
offset: 0,
|
|
limit: 2000,
|
|
});
|
|
});
|
|
|
|
it("keeps valid PDF pages", () => {
|
|
const state = createState();
|
|
|
|
openaiToClaudeResponse({
|
|
id: "chatcmpl-test-pdf",
|
|
model: "test-model",
|
|
choices: [{ delta: { tool_calls: [{ index: 0, id: "toolu_pdf", function: { name: "proxy_Read" } }] } }],
|
|
}, state);
|
|
|
|
const events = openaiToClaudeResponse({
|
|
id: "chatcmpl-test-pdf",
|
|
model: "test-model",
|
|
choices: [{
|
|
delta: { tool_calls: [{ index: 0, function: { arguments: JSON.stringify({ file_path: "F:/repo/doc.pdf", pages: "1-3" }) } }] },
|
|
finish_reason: "tool_calls",
|
|
}],
|
|
}, state);
|
|
|
|
expect(JSON.parse(getInputJsonDelta(events))).toEqual({
|
|
file_path: "F:/repo/doc.pdf",
|
|
pages: "1-3",
|
|
});
|
|
});
|
|
});
|