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

@@ -17,6 +17,11 @@ function mimeToModality(mime: string): Modality | undefined {
export const OUTPUT_TOKEN_MAX = 32_000
// OpenAI Responses `include` value that returns the encrypted reasoning state
// needed for stateless multi-turn reasoning (store: false). Hoisted so every
// branch that requests it stays in lockstep.
const INCLUDE_ENCRYPTED_REASONING = ["reasoning.encrypted_content"] as const
export function sanitizeSurrogates(content: string) {
return content.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD")
}
@@ -756,7 +761,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -790,7 +795,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -803,7 +808,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
include: INCLUDE_ENCRYPTED_REASONING,
},
]),
)
@@ -1134,6 +1139,9 @@ export function options(input: {
if (!input.model.api.id.includes("gpt-5-pro")) {
result["reasoningEffort"] = "medium"
result["reasoningSummary"] = "auto"
if (input.model.api.npm === "@ai-sdk/openai") {
result["include"] = INCLUDE_ENCRYPTED_REASONING
}
}
// Only set textVerbosity for non-chat gpt-5.x models
@@ -1149,7 +1157,7 @@ export function options(input: {
if (input.model.providerID.startsWith("opencode")) {
result["promptCacheKey"] = input.sessionID
result["include"] = ["reasoning.encrypted_content"]
result["include"] = INCLUDE_ENCRYPTED_REASONING
result["reasoningSummary"] = "auto"
}
}

View File

@@ -70,6 +70,14 @@ export function stream(input: StreamInput): StreamResult {
// Integration point with @opencode-ai/llm: native-request lowers session data
// into an LLMRequest, then LLMClient handles route selection and transport.
//
// ProviderTransform.providerOptions builds AI-SDK-shaped options for the
// selected SDK key (e.g. "openai") and the native LLM SDK reads the same
// keys via OpenAIOptions.* (store, reasoningEffort, reasoningSummary,
// include, textVerbosity, promptCacheKey). Both sides intentionally use
// OpenAI's official wire field names, so this is identity, not translation
// — if a field ever needs to differ between the two surfaces, the
// translation belongs here, not split across both packages.
const stream = input.llmClient.stream({
request: LLMNative.request({
model: input.model,