refactor(ai): make OpenAI Responses extend Open Responses (#38681)

This commit is contained in:
Shoubhit Dash 2026-07-24 18:36:35 +05:30 committed by GitHub
commit c5680a206e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 1261 additions and 1067 deletions

View file

@ -0,0 +1,65 @@
import { Schema } from "effect"
import { TextVerbosity, type LLMRequest } from "../../schema"
export const ResponseIncludables = [
"file_search_call.results",
"web_search_call.results",
"web_search_call.action.sources",
"message.input_image.image_url",
"computer_call_output.output.image_url",
"code_interpreter_call.outputs",
"reasoning.encrypted_content",
"message.output_text.logprobs",
] as const
export type ResponseIncludable = (typeof ResponseIncludables)[number]
export const ServiceTiers = ["auto", "default", "flex", "priority"] as const
export type ServiceTier = (typeof ServiceTiers)[number]
const TEXT_VERBOSITY = new Set<string>(["low", "medium", "high"])
const INCLUDABLES = new Set<string>(ResponseIncludables)
const SERVICE_TIERS = new Set<string>(ServiceTiers)
const isTextVerbosity = (value: unknown): value is Schema.Schema.Type<typeof TextVerbosity> =>
typeof value === "string" && TEXT_VERBOSITY.has(value)
const isServiceTier = (value: unknown): value is ServiceTier => typeof value === "string" && SERVICE_TIERS.has(value)
export const ReasoningEffort = Schema.String
export const TextVerbositySchema = TextVerbosity
export const ResponseIncludableSchema = Schema.Literals(ResponseIncludables)
export const ServiceTierSchema = Schema.Literals(ServiceTiers)
export interface Resolved {
readonly instructions?: string
readonly store?: boolean
readonly promptCacheKey?: string
readonly reasoningEffort?: string
readonly reasoningSummary?: "auto" | "concise" | "detailed"
readonly include?: ReadonlyArray<ResponseIncludable>
readonly textVerbosity?: Schema.Schema.Type<typeof TextVerbosity>
readonly serviceTier?: ServiceTier
}
export const resolve = (request: LLMRequest): Resolved => {
const input = request.providerOptions?.[request.model.route.providerMetadataKey ?? "openresponses"]
const include = Array.isArray(input?.include)
? input.include.filter((entry): entry is ResponseIncludable => INCLUDABLES.has(entry))
: []
const reasoningSummary = input?.reasoningSummary
return {
instructions: typeof input?.instructions === "string" ? input.instructions : undefined,
store: typeof input?.store === "boolean" ? input.store : undefined,
promptCacheKey: typeof input?.promptCacheKey === "string" ? input.promptCacheKey : undefined,
reasoningEffort: typeof input?.reasoningEffort === "string" ? input.reasoningEffort : undefined,
reasoningSummary:
reasoningSummary === "auto" || reasoningSummary === "concise" || reasoningSummary === "detailed"
? reasoningSummary
: undefined,
include: include.length > 0 ? include : undefined,
textVerbosity: isTextVerbosity(input?.textVerbosity) ? input.textVerbosity : undefined,
serviceTier: isServiceTier(input?.serviceTier) ? input.serviceTier : undefined,
}
}
export * as OpenResponsesOptions from "./open-responses-options"

View file

@ -1,85 +1,23 @@
import { Schema } from "effect"
import type { LLMRequest, TextVerbosity as TextVerbosityValue } from "../../schema"
import { ReasoningEfforts, TextVerbosity } from "../../schema"
import { ReasoningEfforts } from "../../schema"
import { OpenResponsesOptions } from "./open-responses-options"
export const OpenAIReasoningEfforts = ReasoningEfforts
export type OpenAIReasoningEffort = string
// Mirrors OpenAI's `ResponseIncludable` union from the official SDK. Keep this
// in lockstep with `openai-node/src/resources/responses/responses.ts`.
export const OpenAIResponseIncludables = [
"file_search_call.results",
"web_search_call.results",
"web_search_call.action.sources",
"message.input_image.image_url",
"computer_call_output.output.image_url",
"code_interpreter_call.outputs",
"reasoning.encrypted_content",
"message.output_text.logprobs",
] as const
export type OpenAIResponseIncludable = (typeof OpenAIResponseIncludables)[number]
export const OpenAIServiceTiers = ["auto", "default", "flex", "priority"] as const
export type OpenAIServiceTier = (typeof OpenAIServiceTiers)[number]
export const OpenAIResponseIncludables = OpenResponsesOptions.ResponseIncludables
export type OpenAIResponseIncludable = OpenResponsesOptions.ResponseIncludable
export const OpenAIServiceTiers = OpenResponsesOptions.ServiceTiers
export type OpenAIServiceTier = OpenResponsesOptions.ServiceTier
const TEXT_VERBOSITY = new Set<string>(["low", "medium", "high"])
const INCLUDABLES = new Set<string>(OpenAIResponseIncludables)
const SERVICE_TIERS = new Set<string>(OpenAIServiceTiers)
export const OpenAIReasoningEffort = Schema.String
export const OpenAITextVerbosity = TextVerbosity
export const OpenAIResponseIncludable = Schema.Literals(OpenAIResponseIncludables)
export const OpenAIServiceTier = Schema.Literals(OpenAIServiceTiers)
export const OpenAIReasoningEffort = OpenResponsesOptions.ReasoningEffort
export const OpenAITextVerbosity = OpenResponsesOptions.TextVerbositySchema
export const OpenAIResponseIncludable = OpenResponsesOptions.ResponseIncludableSchema
export const OpenAIServiceTier = OpenResponsesOptions.ServiceTierSchema
export const isReasoningEffort = (effort: unknown): effort is OpenAIReasoningEffort => typeof effort === "string"
const isTextVerbosity = (value: unknown): value is TextVerbosityValue =>
typeof value === "string" && TEXT_VERBOSITY.has(value)
const options = (request: LLMRequest) => request.providerOptions?.openai
export const store = (request: LLMRequest): boolean | undefined => {
const value = options(request)?.store
return typeof value === "boolean" ? value : undefined
}
export const reasoningEffort = (request: LLMRequest): string | undefined => {
const value = options(request)?.reasoningEffort
return typeof value === "string" ? value : undefined
}
export const reasoningSummary = (request: LLMRequest): "auto" | undefined =>
options(request)?.reasoningSummary === "auto" ? "auto" : undefined
// Resolve the OpenAI Responses `include` field. Filters out unknown
// includable values defensively so a typo in upstream config drops the
// invalid entry instead of poisoning the wire body. An empty array (either
// passed directly or produced by filtering) is treated as "no include" and
// returns undefined so the request body omits the field entirely.
export const include = (request: LLMRequest): ReadonlyArray<OpenAIResponseIncludable> | undefined => {
const value = options(request)?.include
if (!Array.isArray(value)) return undefined
const filtered = value.filter((entry): entry is OpenAIResponseIncludable => INCLUDABLES.has(entry))
return filtered.length > 0 ? filtered : undefined
}
export const promptCacheKey = (request: LLMRequest) => {
const value = options(request)?.promptCacheKey
return typeof value === "string" ? value : undefined
}
export const textVerbosity = (request: LLMRequest) => {
const value = options(request)?.textVerbosity
return isTextVerbosity(value) ? value : undefined
}
export const serviceTier = (request: LLMRequest) => {
const value = options(request)?.serviceTier
return typeof value === "string" && SERVICE_TIERS.has(value) ? (value as OpenAIServiceTier) : undefined
}
export const instructions = (request: LLMRequest) => {
const value = options(request)?.instructions
return typeof value === "string" ? value : undefined
}
export const resolve = OpenResponsesOptions.resolve
export * as OpenAIOptions from "./openai-options"

View file

@ -63,6 +63,8 @@ const openAI = (schema: JsonSchema): JsonSchema => {
return isRecord(normalized) ? normalized : { type: "object" }
}
const responses = openAI
const gemini = (schema: JsonSchema): JsonSchema => GeminiToolSchema.convert(schema) ?? {}
const modelCompatibility = (
@ -83,4 +85,5 @@ export const ToolSchemaProjection = {
modelCompatibility,
moonshot,
openAI,
responses,
} as const