Files
OmniRoute/tests/unit/grok-cli-function-call-output-sanitize-7611.test.ts
Ravi Tharuma 23aa75ddd5 fix(grok-cli): sanitize function_call_output before Grok Build dispatch (#7611) (#8030)
* 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>
2026-07-22 07:06:15 -03:00

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/);
});