Skip to content

Commit 5d8860a

Browse files
committed
🤖 fix: surface script errors in LLM transform
- append script error output when present so Codex/LLMs can see failures - cover failure path in transformScriptMessagesForLLM tests _Generated with `mux`_ Change-Id: I72f2f4ab6b5c56f5dc6d1fdf50d14b08c2d148fb Signed-off-by: Thomas Kosiewski <tk@coder.com>
1 parent 20f9bb8 commit 5d8860a

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

.cmux/scripts/web_fetch

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/browser/utils/messages/modelMessageTransform.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ export function transformScriptMessagesForLLM(messages: MuxMessage[]): MuxMessag
234234
llmContent += `\nStdout/Stderr: (no output)`;
235235
}
236236

237+
// Surface script errors for Codex/LLM reviewers even when no output exists.
238+
if ("error" in result) {
239+
const trimmedError = result.error.trim();
240+
if (trimmedError.length > 0) {
241+
llmContent += `\nError:\n${trimmedError}`;
242+
}
243+
}
244+
237245
// EXCLUDE MUX_OUTPUT and MUX_PROMPT from the LLM context for the script message itself.
238246
// MUX_PROMPT is sent as a separate user message by ChatInput, so including it here would be duplication.
239247
// MUX_OUTPUT is intended for user toasts, not LLM context.

src/browser/utils/messages/transformScriptMessagesForLLM.test.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,49 @@ describe("transformScriptMessagesForLLM", () => {
7878
const textPart = result[0].parts[0];
7979
expect(textPart.type).toBe("text");
8080
if (textPart.type === "text") {
81-
expect(textPart.text).toContain("Stdout/Stderr:\nstdout stuff");
8281
expect(textPart.text).not.toContain("MUX_OUTPUT");
8382
expect(textPart.text).not.toContain("User toast");
8483
expect(textPart.text).not.toContain("MUX_PROMPT");
8584
expect(textPart.text).not.toContain("Model prompt");
8685
}
8786
});
87+
88+
it("should surface error details when script fails without output", () => {
89+
const scriptResult: BashToolResult = {
90+
success: false,
91+
exitCode: 2,
92+
wall_duration_ms: 120,
93+
error: "Permission denied",
94+
};
95+
96+
const messages: MuxMessage[] = [
97+
{
98+
id: "script-error",
99+
role: "user",
100+
parts: [{ type: "text", text: "Executed script: /script fail" }],
101+
metadata: {
102+
muxMetadata: {
103+
type: "script-execution",
104+
id: "script-error",
105+
historySequence: 0,
106+
timestamp: 999,
107+
command: "/script fail",
108+
scriptName: "fail.sh",
109+
args: [],
110+
result: scriptResult,
111+
},
112+
},
113+
},
114+
];
115+
116+
const result = transformScriptMessagesForLLM(messages);
117+
expect(result).toHaveLength(1);
118+
const textPart = result[0].parts[0];
119+
expect(textPart.type).toBe("text");
120+
if (textPart.type === "text") {
121+
expect(textPart.text).toContain("Stdout/Stderr: (no output)");
122+
expect(textPart.text).toContain("Error:");
123+
expect(textPart.text).toContain("Permission denied");
124+
}
125+
});
88126
});

0 commit comments

Comments
 (0)