agents/cli: scope nested result unwrapping

This commit is contained in:
Alec Hrdina
2026-04-14 21:32:18 +00:00
committed by Ayaan Zaidi
parent 015e39e3cf
commit 1b41513b3b
2 changed files with 54 additions and 3 deletions

View File

@@ -143,6 +143,7 @@ describe("parseCliJson", () => {
output: "json",
sessionIdFields: ["session_id"],
},
"claude-cli",
);
expect(result).toEqual({
@@ -152,6 +153,34 @@ describe("parseCliJson", () => {
});
});
it("does not unwrap nested result-shaped JSON for non-claude json backends", () => {
const nestedResult = JSON.stringify({
type: "result",
result: JSON.stringify({
type: "result",
result: "actual response text",
}),
});
const result = parseCliJson(
JSON.stringify({
session_id: "gemini-session-nested-json",
result: nestedResult,
}),
{
command: "gemini",
output: "json",
sessionIdFields: ["session_id"],
},
"gemini",
);
expect(result).toEqual({
text: nestedResult,
sessionId: "gemini-session-nested-json",
usage: undefined,
});
});
it("parses nested OpenAI-style cached token details from CLI json payloads", () => {
const result = parseCliJson(
JSON.stringify({

View File

@@ -266,7 +266,25 @@ function pickCliSessionId(
return undefined;
}
export function parseCliJson(raw: string, backend: CliBackendConfig): CliOutput | null {
function shouldUnwrapNestedCliResultText(params: {
backend: CliBackendConfig;
providerId?: string;
parsed: Record<string, unknown>;
}): boolean {
const isClaudeBackend =
(params.providerId && isClaudeCliProvider(params.providerId)) ||
/^claude(?:$|[\\/-])/i.test(params.backend.command.trim());
if (!isClaudeBackend) {
return false;
}
return !Object.hasOwn(params.parsed, "type") || params.parsed.type === "result";
}
export function parseCliJson(
raw: string,
backend: CliBackendConfig,
providerId?: string,
): CliOutput | null {
const parsedRecords = parseJsonRecordCandidates(raw);
if (parsedRecords.length === 0) {
return null;
@@ -285,7 +303,11 @@ export function parseCliJson(raw: string, backend: CliBackendConfig): CliOutput
collectCliText(parsed.result) ||
collectCliText(parsed.response) ||
collectCliText(parsed);
const trimmedText = unwrapNestedCliResultText(nextText).trim();
const trimmedText = (
shouldUnwrapNestedCliResultText({ backend, providerId, parsed })
? unwrapNestedCliResultText(nextText)
: nextText
).trim();
if (trimmedText) {
text = trimmedText;
sawStructuredOutput = true;
@@ -509,7 +531,7 @@ export function parseCliOutput(params: {
);
}
return (
parseCliJson(params.raw, params.backend) ?? {
parseCliJson(params.raw, params.backend, params.providerId) ?? {
text: params.raw.trim(),
sessionId: params.fallbackSessionId,
}