fix(ai): filter empty error assistant messages in transformMessages

When 429/500 errors occur during tool execution, empty assistant messages
with stopReason='error' get persisted. These break the tool_use -> tool_result
chain for Claude/Gemini APIs.

Added centralized filtering in transformMessages to skip assistant messages
with empty content and no tool calls. Provider-level filters remain for
defense-in-depth.
This commit is contained in:
Mario Zechner
2026-01-16 22:34:58 +01:00
parent d2f9ab110c
commit fbb74bb29e
11 changed files with 125 additions and 8 deletions

View File

@@ -135,10 +135,13 @@ const defaultBashOperations: BashOperations = {
export interface BashToolOptions {
/** Custom operations for command execution. Default: local shell */
operations?: BashOperations;
/** Command prefix prepended to every command (e.g., "shopt -s expand_aliases" for alias support) */
commandPrefix?: string;
}
export function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema> {
const ops = options?.operations ?? defaultBashOperations;
const commandPrefix = options?.commandPrefix;
return {
name: "bash",
@@ -151,6 +154,9 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
signal?: AbortSignal,
onUpdate?,
) => {
// Apply command prefix if configured (e.g., "shopt -s expand_aliases" for alias support)
const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
return new Promise((resolve, reject) => {
// We'll stream to a temp file if output gets large
let tempFilePath: string | undefined;
@@ -206,7 +212,7 @@ export function createBashTool(cwd: string, options?: BashToolOptions): AgentToo
}
};
ops.exec(command, cwd, { onData: handleData, signal, timeout })
ops.exec(resolvedCommand, cwd, { onData: handleData, signal, timeout })
.then(({ exitCode }) => {
// Close temp file stream
if (tempFileStream) {