convertToModelMessages

fun convertToModelMessages(messages: List<UIMessage>, ignoreIncompleteToolCalls: Boolean = false): List<ModelMessage>(source)

Convert a list of UI-shape UIMessages back into the model-shape ModelMessage list the LLM expects on the next turn. Mirrors v6's convertToModelMessages (per historical parity gap #5).

Required for any flow that PERSISTS the chat in its rendered form and later wants to RESUME the agent: history replay, crash recovery, subagent continuation, manual edit & re-run.

Conversion rules:

  • UIMessagePart.TextContentPart.Text

  • UIMessagePart.ReasoningContentPart.Reasoning

  • UIMessagePart.ToolUI (static) AND UIMessagePart.DynamicToolUI (runtime) share one rule, dispatched by state:

    • OutputAvailable + preliminary=false → assistant carries ContentPart.ToolCall; a SEPARATE follow-up Tool-role ModelMessage carries ContentPart.ToolResult. (Preliminary snapshots from streamingTool never flow to the model — only the final emission. Preliminary parts are dropped here.)

    • ApprovalRequiredContentPart.ToolApprovalRequest

    • InputStreaming / InputAvailable are INCOMPLETE — drop silently if ignoreIncompleteToolCalls, otherwise throw.

    • Error → drop. The tool failed; the model already saw a ContentPart.ToolResult with isError=true at the time (encoded by the agent loop), no useful re-send shape.

  • UIMessagePart.StepStart, Source, File, Error → drop. No useful model-side representation, or out-of-scope for v0.

Ordering is preserved: each UIMessage with tool calls becomes: Assistant(text, ToolCall...) → Tool(ToolResult) → Tool(ToolResult) → … — which is what the model expects on the next turn.

Parameters

messages

The UI-shape history to convert.

ignoreIncompleteToolCalls

If true, drop tool parts in InputStreaming / InputAvailable state silently. If false (default), throw IllegalStateException when an incomplete tool call is seen — these usually indicate corrupted history.