refactor(llm): simplify provider resolver defaults

This commit is contained in:
Kit Langton
2026-04-28 09:20:42 -04:00
parent b0be03facd
commit 7141036ec4
3 changed files with 46 additions and 41 deletions
+4 -3
View File
@@ -8,7 +8,7 @@ export interface ProviderResolution {
readonly provider: ProviderIDType
readonly protocol: Protocol
readonly baseURL?: string
readonly auth?: ProviderAuth
readonly auth: ProviderAuth
readonly capabilities?: CapabilitiesInput
}
@@ -26,10 +26,11 @@ export interface ProviderResolver {
export const make = (
provider: string | ProviderIDType,
protocol: Protocol,
options: Omit<ProviderResolution, "provider" | "protocol"> = {},
options: Partial<Omit<ProviderResolution, "provider" | "protocol">> = {},
): ProviderResolution => ({
provider: ProviderID.make(provider),
protocol,
auth: options.auth ?? "bearer",
...options,
})
@@ -38,7 +39,7 @@ export const define = (input: ProviderResolver): ProviderResolver => input
export const fixed = (
provider: string | ProviderIDType,
protocol: Protocol,
options: Omit<ProviderResolution, "provider" | "protocol"> = {},
options: Partial<Omit<ProviderResolution, "provider" | "protocol">> = {},
): ProviderResolver => {
const resolution = make(provider, protocol, options)
return define({ id: resolution.provider, resolve: () => resolution })
@@ -18,8 +18,15 @@ export const byProvider: Record<string, ProviderFamily> = Object.fromEntries(
Object.values(families).map((family) => [family.provider, family]),
)
const resolutions = Object.fromEntries(
Object.values(families).map((family) => [
family.provider,
ProviderResolver.make(family.provider, "openai-compatible-chat", { baseURL: family.baseURL }),
]),
)
export const resolve = (provider: string) =>
ProviderResolver.make(provider, "openai-compatible-chat", { baseURL: byProvider[provider]?.baseURL, auth: "bearer" })
resolutions[provider] ?? ProviderResolver.make(provider, "openai-compatible-chat")
export const resolver = ProviderResolver.define({
id: ProviderResolver.make("openai-compatible", "openai-compatible-chat").provider,
+34 -37
View File
@@ -65,7 +65,7 @@ const baseURL = (input: Input, resolution: ProviderResolution, options: Record<s
return resolution.baseURL
}
const authHeader = (auth: ProviderAuth | undefined, apiKey: string | undefined): Record<string, string> => {
const authHeader = (auth: ProviderAuth, apiKey: string | undefined): Record<string, string> => {
if (!apiKey) return {}
if (auth === "none") return {}
if (auth === "anthropic-api-key") return { "x-api-key": apiKey }
@@ -87,7 +87,7 @@ const reasoningEfforts = (input: Input) =>
REASONING_EFFORTS.has(effort as ReasoningEffort),
)
const mergeCapabilities = (base: CapabilitiesInput, override: CapabilitiesInput | undefined): CapabilitiesInput => ({
const mergeCapabilities = (base: CapabilitiesInput, override: CapabilitiesInput): CapabilitiesInput => ({
input: { ...base.input, ...override?.input },
output: { ...base.output, ...override?.output },
tools: { ...base.tools, ...override?.tools },
@@ -95,41 +95,38 @@ const mergeCapabilities = (base: CapabilitiesInput, override: CapabilitiesInput
reasoning: { ...base.reasoning, ...override?.reasoning },
})
const capabilities = (input: Input, resolution: ProviderResolution) =>
LLM.capabilities(
mergeCapabilities(
{
input: {
text: input.model.capabilities.input.text,
image: input.model.capabilities.input.image,
audio: input.model.capabilities.input.audio,
video: input.model.capabilities.input.video,
pdf: input.model.capabilities.input.pdf,
},
output: {
text: input.model.capabilities.output.text,
reasoning: input.model.capabilities.reasoning,
},
tools: {
calls: input.model.capabilities.toolcall,
streamingInput: resolution.protocol !== "gemini" && input.model.capabilities.toolcall,
},
cache: {
// Both Anthropic Messages and Bedrock Converse honour positional cache
// markers — Anthropic via `cache_control` on content blocks, Bedrock via
// its `cachePoint` marker block (added to BedrockConverse in 9d7d518ac).
prompt: ["anthropic-messages", "bedrock-converse"].includes(resolution.protocol),
contentBlocks: ["anthropic-messages", "bedrock-converse"].includes(resolution.protocol),
},
reasoning: {
efforts: reasoningEfforts(input),
summaries: resolution.protocol === "openai-responses",
encryptedContent: resolution.protocol === "openai-responses" || resolution.protocol === "anthropic-messages",
},
},
resolution.capabilities,
),
)
const capabilities = (input: Input, resolution: ProviderResolution) => {
const base: CapabilitiesInput = {
input: {
text: input.model.capabilities.input.text,
image: input.model.capabilities.input.image,
audio: input.model.capabilities.input.audio,
video: input.model.capabilities.input.video,
pdf: input.model.capabilities.input.pdf,
},
output: {
text: input.model.capabilities.output.text,
reasoning: input.model.capabilities.reasoning,
},
tools: {
calls: input.model.capabilities.toolcall,
streamingInput: resolution.protocol !== "gemini" && input.model.capabilities.toolcall,
},
cache: {
// Both Anthropic Messages and Bedrock Converse honour positional cache
// markers — Anthropic via `cache_control` on content blocks, Bedrock via
// its `cachePoint` marker block (added to BedrockConverse in 9d7d518ac).
prompt: ["anthropic-messages", "bedrock-converse"].includes(resolution.protocol),
contentBlocks: ["anthropic-messages", "bedrock-converse"].includes(resolution.protocol),
},
reasoning: {
efforts: reasoningEfforts(input),
summaries: resolution.protocol === "openai-responses",
encryptedContent: resolution.protocol === "openai-responses" || resolution.protocol === "anthropic-messages",
},
}
return LLM.capabilities(resolution.capabilities ? mergeCapabilities(base, resolution.capabilities) : base)
}
export const toModelRef = (input: Input): ModelRef | undefined => {
const options = { ...input.provider.options, ...input.model.options }