fix(llm): split OpenAI reasoning summary blocks (#29000)

This commit is contained in:
Aiden Cline
2026-05-23 20:06:45 -05:00
committed by GitHub
parent 0b3a1c2fdf
commit eb84f461b8
22 changed files with 717 additions and 71 deletions

View File

@@ -336,10 +336,25 @@ const weatherTool = tool({
})
const toolRoundtrip = (
events: ReadonlyArray<LLMEvent>,
call: { readonly id: string; readonly name: string; readonly input: unknown },
result: JSONValue,
): ModelMessage[] => [
{ role: "assistant", content: [{ type: "tool-call", toolCallId: call.id, toolName: call.name, input: call.input }] },
{
role: "assistant",
content: [
...events.filter(LLMEvent.is.reasoningEnd).map((part) => ({
type: "reasoning" as const,
text: events
.filter(LLMEvent.is.reasoningDelta)
.filter((event) => event.id === part.id)
.map((event) => event.text)
.join(""),
providerMetadata: part.providerMetadata,
})),
{ type: "tool-call", toolCallId: call.id, toolName: call.name, input: call.input },
],
},
{
role: "tool",
content: [
@@ -395,7 +410,7 @@ const driveToolLoop = (scenario: RecordedScenario) =>
const turn2 = yield* collect({
...base,
messages: [userMessage, ...toolRoundtrip(toolCall!, WEATHER_RESULT)],
messages: [userMessage, ...toolRoundtrip(turn1, toolCall!, WEATHER_RESULT)],
})
expect(LLMResponse.text({ events: turn2 })).toMatch(/Paris is sunny/i)

View File

@@ -591,7 +591,7 @@ describe("session.llm-native.request", () => {
]),
storedSession.user("Summarize it."),
],
providerOptions: { openai: { store: false, includeEncryptedReasoning: true } },
providerOptions: { openai: { store: false, include: ["reasoning.encrypted_content"] } },
expectedBody: {
input: [
openAIResponses.user("What changed?"),
@@ -608,6 +608,45 @@ describe("session.llm-native.request", () => {
}),
)
it.effect("preserves empty encrypted OpenAI reasoning items before tool output", () =>
expectOpenAIResponsesRequest({
history: [
storedSession.assistant([
storedSession.openaiReasoning("", {
storedAs: "providerMetadata",
itemId: "rs_1",
encryptedContent: "encrypted-state",
}),
]),
],
providerOptions: { openai: { store: false, include: ["reasoning.encrypted_content"] } },
expectedBody: {
input: [{ type: "reasoning", id: "rs_1", summary: [], encrypted_content: "encrypted-state" }],
include: ["reasoning.encrypted_content"],
store: false,
},
}),
)
it.effect("references stored OpenAI reasoning items by id", () =>
expectOpenAIResponsesRequest({
history: [
storedSession.assistant([
storedSession.openaiReasoning("Checked the previous diff.", {
storedAs: "providerMetadata",
itemId: "rs_1",
encryptedContent: null,
}),
]),
],
providerOptions: { openai: { store: true } },
expectedBody: {
input: [{ type: "item_reference", id: "rs_1" }],
store: true,
},
}),
)
it.effect("uses provider fetch override for native OpenAI OAuth requests", () =>
Effect.gen(function* () {
const captures: Array<{ url: string; body: unknown }> = []

View File

@@ -1166,6 +1166,7 @@ describe("session.llm.stream", () => {
expect(capture.body.model).toBe(model.id)
expect(capture.body.stream).toBe(true)
expect((capture.body.reasoning as { effort?: string } | undefined)?.effort).toBe("high")
expect(capture.body.include).toEqual(["reasoning.encrypted_content"])
expect(JSON.stringify(capture.body.input)).toContain("You are a helpful assistant.")
expect(capture.body.input).toContainEqual({ role: "user", content: [{ type: "input_text", text: "Hello" }] })
}),