fix(llm): split OpenAI reasoning summary blocks (#29000)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 }> = []
|
||||
|
||||
@@ -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" }] })
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user