fix(claude-code-cli): surface result text for success errors
This commit is contained in:
parent
791ce1b35e
commit
4189afe8a0
2 changed files with 69 additions and 9 deletions
|
|
@ -118,6 +118,18 @@ function createAssistantStream(): AssistantMessageEventStream {
|
|||
) as AssistantMessageEventStream;
|
||||
}
|
||||
|
||||
export function getResultErrorMessage(result: SDKResultMessage): string {
|
||||
if ("errors" in result && Array.isArray(result.errors) && result.errors.length > 0) {
|
||||
return result.errors.join("; ");
|
||||
}
|
||||
|
||||
if ("result" in result && typeof result.result === "string" && result.result.trim().length > 0) {
|
||||
return result.result.trim();
|
||||
}
|
||||
|
||||
return result.subtype === "success" ? "claude_code_request_failed" : result.subtype;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Claude binary resolution
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -882,11 +894,7 @@ async function pumpSdkMessages(
|
|||
};
|
||||
|
||||
if (result.is_error) {
|
||||
const errText =
|
||||
"errors" in result
|
||||
? (result as any).errors?.join("; ")
|
||||
: result.subtype;
|
||||
finalMessage.errorMessage = errText;
|
||||
finalMessage.errorMessage = getResultErrorMessage(result);
|
||||
stream.push({ type: "error", reason: "error", error: finalMessage });
|
||||
} else {
|
||||
stream.push({ type: "done", reason: "stop", message: finalMessage });
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { join, resolve } from "node:path";
|
|||
import { tmpdir } from "node:os";
|
||||
import {
|
||||
makeStreamExhaustedErrorMessage,
|
||||
getResultErrorMessage,
|
||||
buildPromptFromContext,
|
||||
buildSdkOptions,
|
||||
createClaudeCodeElicitationHandler,
|
||||
|
|
@ -40,6 +41,57 @@ describe("stream-adapter — exhausted stream fallback (#2575)", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("stream-adapter — result error text (#3776)", () => {
|
||||
test("prefers SDK result text when an error arrives with subtype success", () => {
|
||||
const message = getResultErrorMessage({
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
uuid: "uuid-1",
|
||||
session_id: "session-1",
|
||||
duration_ms: 1,
|
||||
duration_api_ms: 1,
|
||||
is_error: true,
|
||||
num_turns: 1,
|
||||
result: 'API Error: 529 {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}',
|
||||
stop_reason: null,
|
||||
total_cost_usd: 0,
|
||||
usage: {
|
||||
input_tokens: 0,
|
||||
output_tokens: 0,
|
||||
cache_read_input_tokens: 0,
|
||||
cache_creation_input_tokens: 0,
|
||||
},
|
||||
});
|
||||
|
||||
assert.match(message, /API Error: 529/);
|
||||
assert.doesNotMatch(message, /^success$/i);
|
||||
});
|
||||
|
||||
test("falls back to a stable classifier when success errors have no text", () => {
|
||||
const message = getResultErrorMessage({
|
||||
type: "result",
|
||||
subtype: "success",
|
||||
uuid: "uuid-2",
|
||||
session_id: "session-2",
|
||||
duration_ms: 1,
|
||||
duration_api_ms: 1,
|
||||
is_error: true,
|
||||
num_turns: 1,
|
||||
result: " ",
|
||||
stop_reason: null,
|
||||
total_cost_usd: 0,
|
||||
usage: {
|
||||
input_tokens: 0,
|
||||
output_tokens: 0,
|
||||
cache_read_input_tokens: 0,
|
||||
cache_creation_input_tokens: 0,
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(message, "claude_code_request_failed");
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Bug #2859 — stateless provider regression tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -598,9 +650,9 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|||
requestedSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
TEST_PASSWORD: {
|
||||
TEST_SECURE_FIELD: {
|
||||
type: "string",
|
||||
title: "TEST_PASSWORD",
|
||||
title: "TEST_SECURE_FIELD",
|
||||
description: "Format: Your secure testing password\nLeave empty to skip.",
|
||||
},
|
||||
},
|
||||
|
|
@ -611,7 +663,7 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|||
const handler = createClaudeCodeElicitationHandler({
|
||||
input: async (_title: string, _placeholder?: string, opts?: { secure?: boolean }) => {
|
||||
inputCalls.push({ opts });
|
||||
return "super-secret";
|
||||
return "example-secure-input";
|
||||
},
|
||||
} as any);
|
||||
assert.ok(handler);
|
||||
|
|
@ -620,7 +672,7 @@ describe("stream-adapter — MCP elicitation bridge", () => {
|
|||
assert.deepEqual(result, {
|
||||
action: "accept",
|
||||
content: {
|
||||
TEST_PASSWORD: "super-secret",
|
||||
TEST_SECURE_FIELD: "example-secure-input",
|
||||
},
|
||||
});
|
||||
assert.equal(inputCalls.length, 1);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue