@@ -122,20 +122,6 @@ function withPartText(part: TextPart | MediaPart, text: string): TextPart {
122122 return { ...part , text } ;
123123}
124124
125- /**
126- * Check if a content array part is a text part ({ type: "text", text: "..." }).
127- */
128- function isTextContentPart ( part : unknown ) : part is { type : 'text' ; text : string } {
129- return (
130- part !== null &&
131- typeof part === 'object' &&
132- 'type' in part &&
133- part . type === 'text' &&
134- 'text' in part &&
135- typeof part . text === 'string'
136- ) ;
137- }
138-
139125/**
140126 * Check if a message has the OpenAI/Anthropic content format.
141127 */
@@ -243,63 +229,6 @@ function truncatePartsMessage(message: PartsMessage, maxBytes: number): unknown[
243229 }
244230}
245231
246- /**
247- * Truncate a message with `content: [...]` array format (Vercel AI SDK, OpenAI multimodal).
248- * Content arrays contain parts like `{ type: "text", text: "..." }`.
249- * Keeps as many complete parts as possible, only truncating text parts if needed.
250- *
251- * @param message - Message with content array property
252- * @param maxBytes - Maximum byte limit
253- * @returns Array with truncated message, or empty array if it doesn't fit
254- */
255- function truncateContentArrayMessage ( message : ContentArrayMessage , maxBytes : number ) : unknown [ ] {
256- const { content } = message ;
257-
258- // Calculate overhead by creating empty text parts (non-text parts keep their size)
259- const emptyContent = content . map ( part => ( isTextContentPart ( part ) ? { ...part , text : '' } : part ) ) ;
260- const overhead = jsonBytes ( { ...message , content : emptyContent } ) ;
261- let remainingBytes = maxBytes - overhead ;
262-
263- if ( remainingBytes <= 0 ) {
264- return [ ] ;
265- }
266-
267- // Include parts until we run out of space
268- const includedParts : ContentArrayMessage [ 'content' ] = [ ] ;
269-
270- for ( const part of content ) {
271- if ( isTextContentPart ( part ) ) {
272- // Text part: check if it fits, truncate if needed
273- const textSize = utf8Bytes ( part . text ) ;
274-
275- if ( textSize <= remainingBytes ) {
276- // Text fits: include it as-is
277- includedParts . push ( part ) ;
278- remainingBytes -= textSize ;
279- } else if ( includedParts . length === 0 ) {
280- // First part doesn't fit: truncate it
281- const truncated = truncateTextByBytes ( part . text , remainingBytes ) ;
282- if ( truncated ) {
283- includedParts . push ( { ...part , text : truncated } ) ;
284- }
285- break ;
286- } else {
287- // Subsequent text part doesn't fit: stop here
288- break ;
289- }
290- } else {
291- // Non-text part (image, etc.): size is already in overhead, include it
292- includedParts . push ( part ) ;
293- }
294- }
295-
296- if ( includedParts . length === 0 ) {
297- return [ ] ;
298- }
299-
300- return [ { ...message , content : includedParts } ] ;
301- }
302-
303232/**
304233 * Truncate a single message to fit within maxBytes.
305234 *
@@ -330,7 +259,8 @@ function truncateSingleMessage(message: unknown, maxBytes: number): unknown[] {
330259 }
331260
332261 if ( isContentArrayMessage ( message ) ) {
333- return truncateContentArrayMessage ( message , maxBytes ) ;
262+ // Content array messages are returned as-is without truncation
263+ return [ message ] ;
334264 }
335265
336266 if ( isPartsMessage ( message ) ) {
0 commit comments