diff --git a/packages/ai/src/protocols/bedrock-converse.ts b/packages/ai/src/protocols/bedrock-converse.ts index 865df6f460c..438f006bae3 100644 --- a/packages/ai/src/protocols/bedrock-converse.ts +++ b/packages/ai/src/protocols/bedrock-converse.ts @@ -348,7 +348,10 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* ( continue } } - messages.push({ role: "user", content }) + const previous = messages.at(-1) + if (previous?.role === "user") + messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] } + else messages.push({ role: "user", content }) continue } @@ -392,7 +395,10 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* ( const cachePoint = BedrockCache.block(breakpoints, part.cache) if (cachePoint) content.push(cachePoint) } - messages.push({ role: "user", content }) + const previous = messages.at(-1) + if (previous?.role === "user") + messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] } + else messages.push({ role: "user", content }) } return messages diff --git a/packages/ai/test/provider/bedrock-converse.test.ts b/packages/ai/test/provider/bedrock-converse.test.ts index 5033caf50a1..4b2ca524b3f 100644 --- a/packages/ai/test/provider/bedrock-converse.test.ts +++ b/packages/ai/test/provider/bedrock-converse.test.ts @@ -255,6 +255,57 @@ describe("Bedrock Converse route", () => { }), ) + it.effect("merges parallel tool results into one user message", () => + Effect.gen(function* () { + const prepared = yield* compileRequest( + LLM.request({ + id: "req_parallel_history", + model, + messages: [ + Message.user("Compare the weather."), + Message.assistant([ + ToolCallPart.make({ id: "tool_paris", name: "lookup", input: { city: "Paris" } }), + ToolCallPart.make({ id: "tool_london", name: "lookup", input: { city: "London" } }), + ]), + Message.tool({ id: "tool_paris", name: "lookup", result: { forecast: "sunny" } }), + Message.tool({ id: "tool_london", name: "lookup", result: { forecast: "rainy" } }), + ], + cache: "none", + }), + ) + + expect(prepared.body.messages).toEqual([ + { role: "user", content: [{ text: "Compare the weather." }] }, + { + role: "assistant", + content: [ + { toolUse: { toolUseId: "tool_paris", name: "lookup", input: { city: "Paris" } } }, + { toolUse: { toolUseId: "tool_london", name: "lookup", input: { city: "London" } } }, + ], + }, + { + role: "user", + content: [ + { + toolResult: { + toolUseId: "tool_paris", + content: [{ json: { forecast: "sunny" } }], + status: "success", + }, + }, + { + toolResult: { + toolUseId: "tool_london", + content: [{ json: { forecast: "rainy" } }], + status: "success", + }, + }, + ], + }, + ]) + }), + ) + it.effect("lowers image content in tool-result messages", () => Effect.gen(function* () { const prepared = yield* compileRequest(