* Ensure all non-final assistant messages have non-empty content. * * The API requires "all messages must have non-empty content except for the * optional final assistant message". This can happen when the model returns * an empty content array. * * For non-final assistant messages with empty
( messages: (UserMessage | AssistantMessage)[], )
| 4931 | * Note: Whitespace-only text content is handled separately by filterWhitespaceOnlyAssistantMessages. |
| 4932 | */ |
| 4933 | function ensureNonEmptyAssistantContent( |
| 4934 | messages: (UserMessage | AssistantMessage)[], |
| 4935 | ): (UserMessage | AssistantMessage)[] { |
| 4936 | if (messages.length === 0) { |
| 4937 | return messages |
| 4938 | } |
| 4939 | |
| 4940 | let hasChanges = false |
| 4941 | const result = messages.map((message, index) => { |
| 4942 | // Skip non-assistant messages |
| 4943 | if (message.type !== 'assistant') { |
| 4944 | return message |
| 4945 | } |
| 4946 | |
| 4947 | // Skip the final message (allowed to be empty for prefill) |
| 4948 | if (index === messages.length - 1) { |
| 4949 | return message |
| 4950 | } |
| 4951 | |
| 4952 | // Check if content is empty |
| 4953 | const content = message.message.content |
| 4954 | if (Array.isArray(content) && content.length === 0) { |
| 4955 | hasChanges = true |
| 4956 | logEvent('tengu_fixed_empty_assistant_content', { |
| 4957 | messageUUID: |
| 4958 | message.uuid as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, |
| 4959 | messageIndex: index, |
| 4960 | }) |
| 4961 | |
| 4962 | return { |
| 4963 | ...message, |
| 4964 | message: { |
| 4965 | ...message.message, |
| 4966 | content: [ |
| 4967 | { type: 'text' as const, text: NO_CONTENT_MESSAGE, citations: [] }, |
| 4968 | ], |
| 4969 | }, |
| 4970 | } |
| 4971 | } |
| 4972 | |
| 4973 | return message |
| 4974 | }) |
| 4975 | |
| 4976 | return hasChanges ? result : messages |
| 4977 | } |
| 4978 | |
| 4979 | /** |
| 4980 | * Filter orphaned thinking-only assistant messages. |
no test coverage detected