mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
* fix(grok-cli): sanitize function_call_output before Grok Build dispatch (#7611) Grok Build cli-chat-proxy rejects Responses bodies when tool-result outputs contain incomplete \u escapes or other malformed JSON text. Sanitize function_call_output.output values in GrokCliExecutor so large agent tool transcripts no longer fail intermittently with 400 body-parse errors. * fix(grok-cli): type test credentials instead of casting through any (#7611) tests/ has no-explicit-any as an ESLint error; the 3 `{ accessToken: "tok" } as any` casts passed to transformRequest() were the proven, non-drift cause of this PR's own "No new ESLint warnings" CI failure. Replace them with a single properly-typed ProviderCredentials literal (all fields on that type are optional, so no cast is needed). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { GrokCliExecutor } from "../../open-sse/executors/grok-cli.ts";
|
|
import type { ProviderCredentials } from "../../open-sse/executors/base.ts";
|
|
|
|
const testCredentials: ProviderCredentials = { accessToken: "tok" };
|
|
|
|
test("#7611: GrokCliExecutor sanitizes incomplete hex escapes in function_call_output", () => {
|
|
const executor = new GrokCliExecutor();
|
|
const body = {
|
|
model: "grok-4.5",
|
|
input: [
|
|
{
|
|
type: "function_call",
|
|
call_id: "call_1",
|
|
name: "read_file",
|
|
arguments: "{}",
|
|
},
|
|
{
|
|
type: "function_call_output",
|
|
call_id: "call_1",
|
|
// incomplete \u escape — the production failure mode
|
|
output: '{"path":"foo","snippet":"bad \\u12"}',
|
|
},
|
|
],
|
|
};
|
|
|
|
const transformed = executor.transformRequest("grok-4.5", body, true, testCredentials) as Record<
|
|
string,
|
|
unknown
|
|
>;
|
|
|
|
const input = transformed.input as Array<Record<string, unknown>>;
|
|
const outputItem = input.find((item) => item.type === "function_call_output");
|
|
assert.ok(outputItem, "function_call_output item should remain");
|
|
assert.equal(typeof outputItem.output, "string");
|
|
// Must be re-parseable as a JSON string payload after sanitization.
|
|
assert.doesNotThrow(() => JSON.parse(JSON.stringify({ output: outputItem.output })));
|
|
assert.doesNotMatch(String(outputItem.output), /\\u12(?![0-9A-Fa-f])/);
|
|
});
|
|
|
|
test("#7611: valid JSON tool outputs are re-serialized cleanly", () => {
|
|
const executor = new GrokCliExecutor();
|
|
const payload = { ok: true, data: ["a", "b"], note: "café" };
|
|
const body = {
|
|
model: "grok-4.5",
|
|
input: [
|
|
{
|
|
type: "function_call_output",
|
|
call_id: "call_2",
|
|
output: JSON.stringify(payload),
|
|
},
|
|
],
|
|
};
|
|
const transformed = executor.transformRequest("grok-4.5", body, false, testCredentials) as Record<
|
|
string,
|
|
unknown
|
|
>;
|
|
const input = transformed.input as Array<Record<string, unknown>>;
|
|
const outputItem = input.find((item) => item.type === "function_call_output");
|
|
assert.deepEqual(JSON.parse(String(outputItem?.output)), payload);
|
|
});
|
|
|
|
test("#7611: array content parts are flattened to text", () => {
|
|
const executor = new GrokCliExecutor();
|
|
const body = {
|
|
model: "grok-4.5",
|
|
input: [
|
|
{
|
|
type: "function_call_output",
|
|
call_id: "call_3",
|
|
output: [
|
|
{ type: "input_text", text: "hello" },
|
|
{ type: "input_text", text: "world" },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
const transformed = executor.transformRequest("grok-4.5", body, false, testCredentials) as Record<
|
|
string,
|
|
unknown
|
|
>;
|
|
const input = transformed.input as Array<Record<string, unknown>>;
|
|
const outputItem = input.find((item) => item.type === "function_call_output");
|
|
assert.equal(typeof outputItem?.output, "string");
|
|
assert.match(String(outputItem?.output), /hello/);
|
|
assert.match(String(outputItem?.output), /world/);
|
|
});
|