refactor(ai): normalize provider option parsing (#38695)

This commit is contained in:
Shoubhit Dash 2026-07-24 19:02:02 +05:30 committed by GitHub
commit d90da82be2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 256 additions and 84 deletions

View file

@ -0,0 +1,57 @@
import { Effect, Schema } from "effect"
import type { LLMRequest } from "../../schema"
import { ProviderShared } from "../shared"
export const ThinkingSchema = Schema.Union([
Schema.Struct({
type: Schema.tag("enabled"),
budget_tokens: Schema.Number,
}),
Schema.Struct({
type: Schema.tag("adaptive"),
display: Schema.optional(Schema.Literals(["summarized", "omitted"])),
}),
Schema.Struct({
type: Schema.tag("disabled"),
}),
])
export type Thinking = Schema.Schema.Type<typeof ThinkingSchema>
export interface Resolved {
readonly thinking?: Thinking
readonly effort?: string
}
export const resolve = Effect.fn("AnthropicOptions.resolve")(function* (request: LLMRequest) {
const input = request.providerOptions?.anthropic
return {
thinking: yield* resolveThinking(input?.thinking),
effort: typeof input?.effort === "string" ? input.effort : undefined,
} satisfies Resolved
})
const resolveThinking = Effect.fn("AnthropicOptions.resolveThinking")(function* (input: unknown) {
if (!ProviderShared.isRecord(input)) return undefined
if (input.type === "adaptive") {
const display =
input.display === "summarized"
? ("summarized" as const)
: input.display === "omitted"
? ("omitted" as const)
: undefined
return { type: "adaptive" as const, ...(display === undefined ? {} : { display }) }
}
if (input.type === "disabled") return { type: "disabled" as const }
if (input.type !== "enabled") return undefined
const budget =
typeof input.budgetTokens === "number"
? input.budgetTokens
: typeof input.budget_tokens === "number"
? input.budget_tokens
: undefined
if (budget === undefined)
return yield* ProviderShared.invalidRequest("Anthropic thinking provider option requires budgetTokens")
return { type: "enabled" as const, budget_tokens: budget }
})
export * as AnthropicOptions from "./anthropic-options"

View file

@ -0,0 +1,27 @@
import { Schema } from "effect"
import type { LLMRequest } from "../../schema"
import { ProviderShared } from "../shared"
export const ThinkingConfigSchema = Schema.Struct({
thinkingBudget: Schema.optional(Schema.Number),
includeThoughts: Schema.optional(Schema.Boolean),
})
export type ThinkingConfig = Schema.Schema.Type<typeof ThinkingConfigSchema>
export interface Resolved {
readonly thinkingConfig?: ThinkingConfig
}
export const resolve = (request: LLMRequest): Resolved => {
const value = request.providerOptions?.gemini?.thinkingConfig
if (!ProviderShared.isRecord(value)) return {}
const thinkingConfig = {
thinkingBudget: typeof value.thinkingBudget === "number" ? value.thinkingBudget : undefined,
includeThoughts: typeof value.includeThoughts === "boolean" ? value.includeThoughts : undefined,
}
return {
thinkingConfig: Object.values(thinkingConfig).some((item) => item !== undefined) ? thinkingConfig : undefined,
}
}
export * as GeminiOptions from "./gemini-options"