mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-20 22:02:38 +00:00
fix(ai): skip errored/aborted assistant messages in transform-messages
Fixes OpenAI Responses 400 error 'reasoning without following item' by skipping errored/aborted assistant messages entirely rather than filtering at the provider level. This covers openai-responses, openai-codex-responses, and future providers. Removes strictResponsesPairing compat option (no longer needed). Closes #838
This commit is contained in:
parent
abb1775ff7
commit
2d27a2c728
10 changed files with 109 additions and 52 deletions
|
|
@ -118,27 +118,23 @@ export function transformMessages<TApi extends Api>(
|
|||
existingToolResultIds = new Set();
|
||||
}
|
||||
|
||||
// Track tool calls from this assistant message
|
||||
// Don't track tool calls from errored messages - they will be dropped by
|
||||
// provider-specific converters, so we shouldn't create synthetic results for them
|
||||
// Skip errored/aborted assistant messages entirely.
|
||||
// These are incomplete turns that shouldn't be replayed:
|
||||
// - May have partial content (reasoning without message, incomplete tool calls)
|
||||
// - Replaying them can cause API errors (e.g., OpenAI "reasoning without following item")
|
||||
// - The model should retry from the last valid state
|
||||
const assistantMsg = msg as AssistantMessage;
|
||||
const toolCalls =
|
||||
assistantMsg.stopReason === "error"
|
||||
? []
|
||||
: (assistantMsg.content.filter((b) => b.type === "toolCall") as ToolCall[]);
|
||||
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Track tool calls from this assistant message
|
||||
const toolCalls = assistantMsg.content.filter((b) => b.type === "toolCall") as ToolCall[];
|
||||
if (toolCalls.length > 0) {
|
||||
pendingToolCalls = toolCalls;
|
||||
existingToolResultIds = new Set();
|
||||
}
|
||||
|
||||
// Skip empty assistant messages (no content and no tool calls)
|
||||
// This handles error responses (e.g., 429/500) that produced no content
|
||||
// All providers already filter these in convertMessages, but we do it here
|
||||
// centrally to prevent issues with the tool_use -> tool_result chain
|
||||
if (assistantMsg.content.length === 0 && toolCalls.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push(msg);
|
||||
} else if (msg.role === "toolResult") {
|
||||
existingToolResultIds.add(msg.toolCallId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue