fix(ai,agent,coding-agent): normalize null message content at ingestion boundaries (#6343)

The Message types require content to always be present, but untyped JS
extension tools, hand-built histories, and old or hand-edited session
files can violate that contract, crashing rendering, compaction, and
provider request conversion with 'content is not iterable'.

Normalize null/missing content to an empty array at the ingestion
boundaries instead of guarding every consumer:

- transformMessages (choke point before every provider request)
- createToolResultMessage in the agent loop
- session entry loading (message and custom_message entries)
- extension custom messages (sendCustomMessage, before_agent_start)
- message_end extension replacements

fixes #6259, fixes #6276
This commit is contained in:
Armin Ronacher
2026-07-06 20:47:08 +02:00
committed by GitHub
parent 6efc09b7eb
commit 8c0ccd14b3
6 changed files with 264 additions and 7 deletions
+4 -1
View File
@@ -68,7 +68,10 @@ export function transformMessages<TApi extends Api>(
): Message[] {
// Build a map of original tool call IDs to normalized IDs
const toolCallIdMap = new Map<string, string>();
const imageAwareMessages = downgradeUnsupportedImages(messages, model);
// Normalize null/undefined content from untyped callers (custom tools, hand-built
// histories, old session files) so downstream code can rely on the type contract.
const normalizedMessages = messages.map((msg) => (msg.content == null ? { ...msg, content: [] } : msg));
const imageAwareMessages = downgradeUnsupportedImages(normalizedMessages, model);
// First pass: transform messages (unsupported image downgrade, thinking blocks, tool call ID normalization)
const transformed = imageAwareMessages.map((msg) => {