Skip to content

Order of message parts get mixed in onFinish() #5275

Closed
@mikkokut

Description

@mikkokut

Description

📄 Description

When using @ai-sdk/vue's useChat() composable with streamText() from ai, there is an inconsistency in the order of message parts between the streamed response and the streamText({onFinish}) callback.

This causes issues with rendering messages consistently in chat UIs after reloads.


⚠️ Problem

If a message includes tool invocations, the order of parts (e.g., text vs. tool-calls) can differ between:

  1. Streamed message parts (received progressively)
  2. Final message in the onFinish (streamText()) callback

📎 Example

Streamed events:

f: {"messageId":"msg-llkj9PNWMkILH5gkJRFMjlu3"}
9: {"toolCallId":"ezv9IDtNtQrqvptU","toolName":"updateState","args":{"op":"replace","path":"/basic/document_name/fi","value":"Testing testing"}}
a: {"toolCallId":"ezv9IDtNtQrqvptU","result":"State updated."}
0: "\n"
e: {"finishReason":"tool-calls","usage":{"promptTokens":2405,"completionTokens":17},"isContinued":false}
d: {"finishReason":"tool-calls","usage":{"promptTokens":2405,"completionTokens":17}}

Resulting message in useChat() messages array:

{
  "id": "msg-llkj9PNWMkILH5gkJRFMjlu3",
  "createdAt": "...",
  "role": "assistant",
  "content": "\n",
  "parts": [
    {
      "type": "tool-invocation",
      "toolInvocation": {
        "state": "result",
        "step": 0,
        "toolCallId": "ezv9IDtNtQrqvptU",
        "toolName": "updateState",
        "args": {
          "op": "replace",
          "path": "/basic/document_name/fi",
          "value": "Testing testing"
        },
        "result": "State updated."
      }
    },
    { "type": "text", "text": "\n" }
  ],
  "toolInvocations": [
    {
      "state": "result",
      "step": 0,
      "toolCallId": "ezv9IDtNtQrqvptU",
      "toolName": "updateState",
      "args": {
        "op": "replace",
        "path": "/basic/document_name/fi",
        "value": "Testing testing"
      },
      "result": "State updated."
    }
  ],
  "revisionId": "ogxXwFFQmJomF6lT"
}

Message in onFinish callback:

{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "\n"
    },
    {
      "type": "tool-call",
      "toolCallId": "HK5S5IJB24yscGaa",
      "toolName": "updateState",
      "args": {
        "op": "replace",
        "path": "/basic/document_name/fi",
        "value": "Testing"
      }
    }
  ],
  "id": "msg-GnW9lDH1sdfeDxeXVcSA0LN0"
}

🔍 Suspected Cause

The issue likely originates from toResponseMessages(), where the transformation logic reorders message parts.


✅ Expected Behavior

The order of message parts (text, tool-call, etc.) should remain consistent between:

  • Streamed message assembly (useChat internal state), and
  • Final message passed to streamText({onFinish}) callback.

🙏 Request

Please consider ensuring toResponseMessages() maintains a deterministic and consistent part ordering in both streamed and finalized responses.

Code example

No response

AI provider

@ai-sdk/google 1.1.12

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai/corebugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions