fix: Collapse all-text arrays to string for DeepSeek compatibility (#806)

Fixes #774. When tool_result content contains multiple text blocks,
they were serialized as arrays instead of strings, causing DeepSeek
to reject the request with 400 error.

Changes:
- convertToolResultContent: collapse all-text arrays to joined string
- convertContentBlocks: defensive collapse for user/assistant messages
- Arrays with images are preserved (not collapsed)

Tests: 3 new tests added, 53 pass, 0 fail

Co-authored-by: nick.mesen <nickmesen@users.noreply.github.com>
This commit is contained in:
nickmesen
2026-04-21 09:17:12 -06:00
committed by GitHub
parent e908864da7
commit 761924daa7
2 changed files with 239 additions and 0 deletions

View File

@@ -291,6 +291,15 @@ function convertToolResultContent(
const text = parts[0].text ?? ''
return isError ? `Error: ${text}` : text
}
// Collapse arrays of only text blocks into a single string for DeepSeek
// compatibility (issue #774). DeepSeek rejects arrays in role: "tool" messages.
const allText = parts.every(p => p.type === 'text')
if (allText) {
const text = parts.map(p => p.text ?? '').join('\n\n')
return isError ? `Error: ${text}` : text
}
if (isError && parts[0]?.type === 'text') {
parts[0] = { ...parts[0], text: `Error: ${parts[0].text ?? ''}` }
} else if (isError) {
@@ -349,6 +358,14 @@ function convertContentBlocks(
if (parts.length === 0) return ''
if (parts.length === 1 && parts[0].type === 'text') return parts[0].text ?? ''
// Collapse arrays of only text blocks into a single string for DeepSeek
// compatibility (issue #774).
const allText = parts.every(p => p.type === 'text')
if (allText) {
return parts.map(p => p.text ?? '').join('\n\n')
}
return parts
}