import { Effect, Schema } from "effect" import { Route, type RouteDefaultsInput } from "../route/client" import { Endpoint } from "../route/endpoint" import { Framing } from "../route/framing" import { Protocol } from "../route/protocol" import { AuthOptions, type ProviderAuthOption } from "../route/auth-options" import { ProviderID, type ModelID, type ProviderOptions } from "../schema" import * as OpenAICompatibleProfiles from "./openai-compatible-profile" import * as OpenAIChat from "../protocols/openai-chat" import { isRecord } from "../protocols/shared" export const profile = OpenAICompatibleProfiles.profiles.openrouter export const id = ProviderID.make(profile.provider) const ADAPTER = "openrouter" export interface OpenRouterOptions { readonly [key: string]: unknown readonly usage?: boolean | Record readonly reasoning?: Record readonly promptCacheKey?: string } export type OpenRouterProviderOptionsInput = ProviderOptions & { readonly openrouter?: OpenRouterOptions } export type ModelOptions = Omit & ProviderAuthOption<"optional"> & { readonly baseURL?: string readonly providerOptions?: OpenRouterProviderOptionsInput } const OpenRouterBody = Schema.StructWithRest(Schema.Struct(OpenAIChat.bodyFields), [ Schema.Record(Schema.String, Schema.Any), ]) export type OpenRouterBody = Schema.Schema.Type export const protocol = Protocol.make({ id: "openrouter-chat", body: { schema: OpenRouterBody, from: (request) => OpenAIChat.protocol.body.from(request).pipe( Effect.map( (body) => ({ ...body, ...bodyOptions(request.providerOptions?.openrouter), }) as OpenRouterBody, ), ), }, stream: OpenAIChat.protocol.stream, }) const bodyOptions = (input: unknown) => { const openrouter = isRecord(input) ? input : {} return { ...(openrouter.usage === true ? { usage: { include: true } } : isRecord(openrouter.usage) ? { usage: openrouter.usage } : {}), ...(isRecord(openrouter.reasoning) ? { reasoning: openrouter.reasoning } : {}), ...(typeof openrouter.promptCacheKey === "string" ? { prompt_cache_key: openrouter.promptCacheKey } : {}), } } export const route = Route.make({ id: ADAPTER, provider: profile.provider, protocol, endpoint: Endpoint.path("/chat/completions", { baseURL: profile.baseURL }), framing: Framing.sse, }) export const routes = [route] const configuredRoute = (input: ModelOptions) => { const { apiKey: _, auth: _auth, baseURL, ...rest } = input return route.with({ ...rest, endpoint: { baseURL: baseURL ?? profile.baseURL }, auth: AuthOptions.bearer(input, "OPENROUTER_API_KEY"), }) } export const configure = (input: ModelOptions = {}) => { const route = configuredRoute(input) return { id, model: (modelID: string | ModelID) => route.model({ id: modelID }), configure, } } export const provider = configure() export const model = provider.model