fix(ai): omit empty Bedrock system blocks (#46294)

This commit is contained in:
Aiden Cline 2026-08-30 14:38:51 -05:00 committed by GitHub
parent 583a1a2b6f
commit ef50e0b6d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 2 deletions

View file

@ -410,7 +410,12 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
const lowerSystem = (
breakpoints: BedrockCache.Breakpoints,
system: ReadonlyArray<LLMRequest["system"][number]>,
): BedrockSystemBlock[] => system.flatMap((part) => textWithCache(breakpoints, part.text, part.cache))
) => {
const content = system
.filter((part) => part.text.length > 0)
.flatMap((part) => textWithCache(breakpoints, part.text, part.cache))
return content.length === 0 ? undefined : content
}
const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request: LLMRequest) {
const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined
@ -427,7 +432,7 @@ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request:
toolChoice,
}
})()
const system = request.system.length === 0 ? undefined : lowerSystem(breakpoints, request.system)
const system = lowerSystem(breakpoints, request.system)
const messages = yield* lowerMessages(request, breakpoints)
if (breakpoints.dropped > 0) {
yield* Effect.logWarning(

View file

@ -125,6 +125,50 @@ describe("Bedrock Converse route", () => {
}),
)
it.effect("omits empty initial system blocks", () =>
Effect.gen(function* () {
const empty = yield* compileRequest(LLM.request({ model, system: "", prompt: "hello" }))
const cachedEmpty = yield* compileRequest(
LLM.request({
model,
system: [{ type: "text", text: "", cache: new CacheHint({ type: "ephemeral" }) }],
prompt: "hello",
cache: "none",
}),
)
expect(empty.body.system).toBeUndefined()
expect(cachedEmpty.body.system).toBeUndefined()
}),
)
it.effect("omits empty system blocks while preserving order and cache hints", () =>
Effect.gen(function* () {
const cache = new CacheHint({ type: "ephemeral" })
const prepared = yield* compileRequest(
LLM.request({
model,
system: [
{ type: "text", text: "", cache },
{ type: "text", text: "First." },
{ type: "text", text: " " },
{ type: "text", text: "" },
{ type: "text", text: "Second.", cache },
],
prompt: "hello",
cache: "none",
}),
)
expect(prepared.body.system).toEqual([
{ text: "First." },
{ text: " " },
{ text: "Second." },
{ cachePoint: { type: "default" } },
])
}),
)
it.effect("passes topK through additionalModelRequestFields as top_k", () =>
Effect.gen(function* () {
const prepared = yield* compileRequest(