MCPcopy Create free account
hub / github.com/TanStack/ai / buildAssistantMessages

Function buildAssistantMessages

packages/ai/src/activities/chat/messages.ts:229–388  ·  view source on GitHub ↗

* Build ModelMessages for an assistant UIMessage, preserving the * sequential interleaving of text, tool calls, and tool results. * * Walks parts in order. Text and tool-call parts accumulate into the * current "segment". When a tool-result part is encountered, the * current segment is flushed

(uiMessage: UIMessage)

Source from the content-addressed store, hash-verified

227 * result is emitted as a tool message.
228 */
229function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
230 const messageList: Array<ModelMessage> = []
231 let current = createSegment()
232 let pendingThinking: Array<{ content: string; signature?: string }> = []
233
234 // Track emitted tool result IDs to avoid duplicates.
235 // A tool call can have BOTH an explicit tool-result part AND an output
236 // field on the tool-call part. We only want one per tool call ID.
237 const emittedToolResultIds = new Set<string>()
238
239 function flushSegment(): void {
240 const content = collapseContentParts(current.contentParts)
241 const hasContent = content !== null
242 const hasToolCalls = current.toolCalls.length > 0
243
244 if (hasContent || hasToolCalls) {
245 messageList.push({
246 role: 'assistant',
247 content,
248 ...(hasToolCalls && { toolCalls: current.toolCalls }),
249 ...(pendingThinking.length > 0 && { thinking: pendingThinking }),
250 })
251 pendingThinking = []
252 }
253 current = createSegment()
254 }
255
256 for (const part of uiMessage.parts) {
257 switch (part.type) {
258 case 'text':
259 case 'image':
260 case 'audio':
261 case 'video':
262 case 'document':
263 current.contentParts.push(part)
264 break
265
266 case 'tool-call':
267 if (isToolCallIncluded(part)) {
268 current.toolCalls.push({
269 id: part.id,
270 type: 'function' as const,
271 function: {
272 name: part.name,
273 arguments: part.arguments,
274 },
275 ...(part.metadata !== undefined && { metadata: part.metadata }),
276 })
277 }
278 break
279
280 case 'tool-result':
281 // Flush the current assistant segment before emitting the tool result
282 flushSegment()
283
284 // Emit the tool result
285 if (
286 (part.state === 'complete' || part.state === 'error') &&

Callers 1

uiMessageToModelMessagesFunction · 0.85

Calls 7

normalizeToolResultFunction · 0.90
createSegmentFunction · 0.85
isToolCallIncludedFunction · 0.85
flushSegmentFunction · 0.85
safeJsonStringifyFunction · 0.85
hasMethod · 0.80
pushMethod · 0.45

Tested by

no test coverage detected