diff --git a/langchain-core/src/messages/base.ts b/langchain-core/src/messages/base.ts
index 41a7cb2c2f70..47b4374c9f0f 100644
--- a/langchain-core/src/messages/base.ts
+++ b/langchain-core/src/messages/base.ts
@@ -127,8 +127,12 @@ export function mergeContent(
     }
     // If both are arrays
   } else if (Array.isArray(secondContent)) {
-    return [...firstContent, ...secondContent];
-    // If the first content is a list and second is a string
+    return (
+      _mergeLists(firstContent, secondContent) ?? [
+        ...firstContent,
+        ...secondContent,
+      ]
+    );
   } else {
     // Otherwise, add the second content as a new element of the list
     return [...firstContent, { type: "text", text: secondContent }];
@@ -259,8 +263,12 @@ export function _mergeDicts(
         `field[${key}] already exists in the message chunk, but with a different type.`
       );
     } else if (typeof merged[key] === "string") {
-      merged[key] = (merged[key] as string) + value;
-    } else if (!Array.isArray(merged[key]) && typeof merged[key] === "object") {
+      if (key === "type") {
+        // Do not merge 'type' fields
+        continue;
+      }
+      merged[key] += value;
+    } else if (typeof merged[key] === "object" && !Array.isArray(merged[key])) {
       merged[key] = _mergeDicts(merged[key], value);
     } else if (Array.isArray(merged[key])) {
       merged[key] = _mergeLists(merged[key], value);
@@ -297,6 +305,13 @@ export function _mergeLists(left?: any[], right?: any[]) {
         } else {
           merged.push(item);
         }
+      } else if (
+        typeof item === "object" &&
+        "text" in item &&
+        item.text === ""
+      ) {
+        // No-op - skip empty text blocks
+        continue;
       } else {
         merged.push(item);
       }
diff --git a/langchain-core/src/messages/tests/base_message.test.ts b/langchain-core/src/messages/tests/base_message.test.ts
index fb6f3797f31f..2a46f2fe014e 100644
--- a/langchain-core/src/messages/tests/base_message.test.ts
+++ b/langchain-core/src/messages/tests/base_message.test.ts
@@ -1,10 +1,11 @@
-import { test } from "@jest/globals";
+import { test, describe, it, expect } from "@jest/globals";
 import { ChatPromptTemplate } from "../../prompts/chat.js";
 import {
   HumanMessage,
   AIMessage,
   ToolMessage,
   ToolMessageChunk,
+  AIMessageChunk,
 } from "../index.js";
 import { load } from "../../load/index.js";
 
@@ -193,3 +194,143 @@ test("Can concat raw_output (object) of ToolMessageChunk", () => {
     bar: "baz",
   });
 });
+
+describe("Complex AIMessageChunk concat", () => {
+  it("concatenates content arrays of strings", () => {
+    expect(
+      new AIMessageChunk({
+        content: [{ type: "text", text: "I am" }],
+        id: "ai4",
+      }).concat(
+        new AIMessageChunk({ content: [{ type: "text", text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        id: "ai4",
+        content: [
+          { type: "text", text: "I am" },
+          { type: "text", text: " indeed." },
+        ],
+      })
+    );
+  });
+
+  it("concatenates mixed content arrays", () => {
+    expect(
+      new AIMessageChunk({
+        content: [{ index: 0, type: "text", text: "I am" }],
+      }).concat(
+        new AIMessageChunk({ content: [{ type: "text", text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [
+          { index: 0, type: "text", text: "I am" },
+          { type: "text", text: " indeed." },
+        ],
+      })
+    );
+  });
+
+  it("merges content arrays with same index", () => {
+    expect(
+      new AIMessageChunk({ content: [{ index: 0, text: "I am" }] }).concat(
+        new AIMessageChunk({ content: [{ index: 0, text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({ content: [{ index: 0, text: "I am indeed." }] })
+    );
+  });
+
+  it("does not merge when one chunk is missing an index", () => {
+    expect(
+      new AIMessageChunk({ content: [{ index: 0, text: "I am" }] }).concat(
+        new AIMessageChunk({ content: [{ text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [{ index: 0, text: "I am" }, { text: " indeed." }],
+      })
+    );
+  });
+
+  it("does not create a holey array when there's a gap between indexes", () => {
+    expect(
+      new AIMessageChunk({ content: [{ index: 0, text: "I am" }] }).concat(
+        new AIMessageChunk({ content: [{ index: 2, text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [
+          { index: 0, text: "I am" },
+          { index: 2, text: " indeed." },
+        ],
+      })
+    );
+  });
+
+  it("does not merge content arrays with separate indexes", () => {
+    expect(
+      new AIMessageChunk({ content: [{ index: 0, text: "I am" }] }).concat(
+        new AIMessageChunk({ content: [{ index: 1, text: " indeed." }] })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [
+          { index: 0, text: "I am" },
+          { index: 1, text: " indeed." },
+        ],
+      })
+    );
+  });
+
+  it("merges content arrays with same index and type", () => {
+    expect(
+      new AIMessageChunk({
+        content: [{ index: 0, text: "I am", type: "text_block" }],
+      }).concat(
+        new AIMessageChunk({
+          content: [{ index: 0, text: " indeed.", type: "text_block" }],
+        })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [{ index: 0, text: "I am indeed.", type: "text_block" }],
+      })
+    );
+  });
+
+  it("merges content arrays with same index and different types without updating type", () => {
+    expect(
+      new AIMessageChunk({
+        content: [{ index: 0, text: "I am", type: "text_block" }],
+      }).concat(
+        new AIMessageChunk({
+          content: [{ index: 0, text: " indeed.", type: "text_block_delta" }],
+        })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [{ index: 0, text: "I am indeed.", type: "text_block" }],
+      })
+    );
+  });
+
+  it("concatenates empty string content and merges other fields", () => {
+    expect(
+      new AIMessageChunk({
+        content: [{ index: 0, type: "text", text: "I am" }],
+      }).concat(
+        new AIMessageChunk({
+          content: [{ type: "text", text: "" }],
+          response_metadata: { extra: "value" },
+        })
+      )
+    ).toEqual(
+      new AIMessageChunk({
+        content: [{ index: 0, type: "text", text: "I am" }],
+        response_metadata: { extra: "value" },
+      })
+    );
+  });
+});