Skip to content

Commit 3d2dad7

Browse files
authored
chore(core/v0): fix chunks constructed with tool calls + chunks (#9256)
1 parent bbbe520 commit 3d2dad7

File tree

4 files changed

+67
-32
lines changed

4 files changed

+67
-32
lines changed

.changeset/stale-chefs-roll.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@langchain/core": patch
3+
---
4+
5+
fix chunks constructed with tool calls + chunks

dependency_range_tests/scripts/langchain/test-with-latest-deps.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ cd /app
2222
node /updater_script/update_resolutions_latest.js
2323

2424
yarn
25-
yarn add @langchain/core
25+
yarn add @langchain/core@^0.3
2626

2727
# Check the test command completes successfully
2828
NODE_OPTIONS=--experimental-vm-modules yarn run jest --testPathIgnorePatterns=\\.int\\.test.ts --testTimeout 30000 --maxWorkers=50%

langchain-core/src/messages/ai.ts

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,10 @@ export class AIMessageChunk extends BaseMessageChunk {
259259
invalid_tool_calls: [],
260260
tool_call_chunks: [],
261261
};
262-
} else if (fields.tool_call_chunks === undefined) {
262+
} else if (
263+
fields.tool_call_chunks === undefined ||
264+
fields.tool_call_chunks.length === 0
265+
) {
263266
initParams = {
264267
...fields,
265268
tool_calls: fields.tool_calls ?? [],
@@ -271,37 +274,35 @@ export class AIMessageChunk extends BaseMessageChunk {
271274
: undefined,
272275
};
273276
} else {
274-
const groupedToolCallChunks = fields.tool_call_chunks.reduce(
275-
(acc, chunk) => {
276-
const matchedChunkIndex = acc.findIndex(([match]) => {
277-
// If chunk has an id and index, match if both are present
278-
if (
279-
"id" in chunk &&
280-
chunk.id &&
281-
"index" in chunk &&
282-
chunk.index !== undefined
283-
) {
284-
return chunk.id === match.id && chunk.index === match.index;
285-
}
286-
// If chunk has an id, we match on id
287-
if ("id" in chunk && chunk.id) {
288-
return chunk.id === match.id;
289-
}
290-
// If chunk has an index, we match on index
291-
if ("index" in chunk && chunk.index !== undefined) {
292-
return chunk.index === match.index;
293-
}
294-
return false;
295-
});
296-
if (matchedChunkIndex !== -1) {
297-
acc[matchedChunkIndex].push(chunk);
298-
} else {
299-
acc.push([chunk]);
277+
const toolCallChunks = fields.tool_call_chunks ?? [];
278+
const groupedToolCallChunks = toolCallChunks.reduce((acc, chunk) => {
279+
const matchedChunkIndex = acc.findIndex(([match]) => {
280+
// If chunk has an id and index, match if both are present
281+
if (
282+
"id" in chunk &&
283+
chunk.id &&
284+
"index" in chunk &&
285+
chunk.index !== undefined
286+
) {
287+
return chunk.id === match.id && chunk.index === match.index;
300288
}
301-
return acc;
302-
},
303-
[] as ToolCallChunk[][]
304-
);
289+
// If chunk has an id, we match on id
290+
if ("id" in chunk && chunk.id) {
291+
return chunk.id === match.id;
292+
}
293+
// If chunk has an index, we match on index
294+
if ("index" in chunk && chunk.index !== undefined) {
295+
return chunk.index === match.index;
296+
}
297+
return false;
298+
});
299+
if (matchedChunkIndex !== -1) {
300+
acc[matchedChunkIndex].push(chunk);
301+
} else {
302+
acc.push([chunk]);
303+
}
304+
return acc;
305+
}, [] as ToolCallChunk[][]);
305306

306307
const toolCalls: ToolCall[] = [];
307308
const invalidToolCalls: InvalidToolCall[] = [];

langchain-core/src/messages/tests/ai.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,35 @@ import { describe, it, expect } from "@jest/globals";
22
import { AIMessageChunk } from "../ai.js";
33

44
describe("AIMessageChunk", () => {
5+
describe("constructor", () => {
6+
it("can be constructed with tool calls using basic params", () => {
7+
const chunk = new AIMessageChunk({
8+
content: "",
9+
tool_calls: [
10+
{
11+
name: "get_weather",
12+
args: {
13+
location: "San Francisco",
14+
},
15+
},
16+
],
17+
invalid_tool_calls: [],
18+
tool_call_chunks: [],
19+
additional_kwargs: {},
20+
response_metadata: {},
21+
});
22+
expect(chunk.tool_calls).toHaveLength(1);
23+
expect(chunk.tool_calls).toEqual([
24+
{
25+
name: "get_weather",
26+
args: {
27+
location: "San Francisco",
28+
},
29+
},
30+
]);
31+
});
32+
});
33+
534
it("should properly merge tool call chunks that have matching indices and ids", () => {
635
const chunk1 = new AIMessageChunk({
736
content: "",

0 commit comments

Comments
 (0)