瀏覽代碼

refactor(ai): limit provider option inference (#39510)

Shoubhit Dash 2 周之前
父節點
當前提交
8c3e06798c
共有 3 個文件被更改,包括 15 次插入48 次删除
  1. 6 19
      packages/ai/src/route/client.ts
  2. 8 13
      packages/ai/src/schema/options.ts
  3. 1 16
      packages/ai/test/llm-option-types.types.ts

+ 6 - 19
packages/ai/src/route/client.ts

@@ -45,9 +45,7 @@ export interface Route<Body, Prepared = unknown> {
   readonly defaults: RouteDefaults
   readonly body: RouteBody<Body>
   readonly with: (patch: RoutePatch<Body, Prepared>) => Route<Body, Prepared>
-  readonly model: <Options extends ProviderOptions = ProviderOptions>(
-    input: RouteMappedModelInput<Options>,
-  ) => Model<Options>
+  readonly model: <Options extends ProviderOptions = ProviderOptions>(input: RouteMappedModelInput) => Model<Options>
   readonly prepareTransport: (body: Body, request: LLMRequest) => Effect.Effect<Prepared, LLMError>
   readonly streamPrepared: (
     prepared: Prepared,
@@ -64,15 +62,9 @@ export type AnyRoute = Route<any, any>
 
 export type HttpOptionsInput = HttpOptions.Input
 
-export type RouteModelInput<Options extends ProviderOptions = ProviderOptions> = Omit<
-  Model.Input<Options>,
-  "provider" | "route"
->
+export type RouteModelInput = Omit<Model.Input, "provider" | "route">
 
-export type RouteRoutedModelInput<Options extends ProviderOptions = ProviderOptions> = Omit<
-  Model.Input<Options>,
-  "route"
->
+export type RouteRoutedModelInput = Omit<Model.Input, "route">
 
 export interface RouteDefaults {
   readonly headers?: Record<string, string>
@@ -98,14 +90,9 @@ export interface RoutePatch<Body, Prepared> extends RouteDefaultsInput {
   readonly endpoint?: EndpointPatch<Body>
 }
 
-type RouteMappedModelInput<Options extends ProviderOptions = ProviderOptions> =
-  | RouteModelInput<Options>
-  | RouteRoutedModelInput<Options>
+type RouteMappedModelInput = RouteModelInput | RouteRoutedModelInput
 
-const makeRouteModel = <Options extends ProviderOptions = ProviderOptions>(
-  route: AnyRoute,
-  mapped: RouteMappedModelInput<Options>,
-) => {
+const makeRouteModel = <Options extends ProviderOptions = ProviderOptions>(route: AnyRoute, mapped: RouteMappedModelInput) => {
   const provider = route.provider ?? ("provider" in mapped ? mapped.provider : undefined)
   if (!provider) throw new Error(`Route.model(${route.id}) requires a provider`)
   if (!endpointBaseURL(route.endpoint))
@@ -297,7 +284,7 @@ function makeFromTransport<Body, Prepared, Frame, Event, State>(
           defaults: mergeRouteDefaults(route.defaults, defaults),
         })
       },
-      model: <Options extends ProviderOptions = ProviderOptions>(input: RouteMappedModelInput<Options>) =>
+      model: <Options extends ProviderOptions = ProviderOptions>(input: RouteMappedModelInput) =>
         makeRouteModel<Options>(route, input),
       prepareTransport: (body, request) =>
         routeInput.transport.prepare({

+ 8 - 13
packages/ai/src/schema/options.ts

@@ -139,17 +139,15 @@ export class ModelDefaults extends Schema.Class<ModelDefaults>("LLM.ModelDefault
   generation: Schema.optional(GenerationOptions),
   providerOptions: Schema.optional(ProviderOptions),
   http: Schema.optional(HttpOptions),
-}) {
-  declare protected readonly _ModelDefaults: void
-}
+}) {}
 
 export namespace ModelDefaults {
-  export type Input<Options extends ProviderOptions = ProviderOptions> =
+  export type Input =
     | ModelDefaults
     | {
         readonly limits?: ModelLimits.Input
         readonly generation?: GenerationOptions.Input
-        readonly providerOptions?: Options
+        readonly providerOptions?: ProviderOptions
         readonly http?: HttpOptions.Input
       }
 
@@ -196,7 +194,7 @@ export class Model<Options extends ProviderOptions = ProviderOptions> {
     this.compatibility = input.compatibility
   }
 
-  static make<Options extends ProviderOptions = ProviderOptions>(input: Model.Input<Options>) {
+  static make<Options extends ProviderOptions = ProviderOptions>(input: Model.Input) {
     return new Model<Options>({
       id: ModelID.make(input.id),
       provider: ProviderID.make(input.provider),
@@ -216,7 +214,7 @@ export class Model<Options extends ProviderOptions = ProviderOptions> {
     }
   }
 
-  static update<Options extends ProviderOptions>(model: Model<Options>, patch: Partial<Model.Input<Options>>) {
+  static update<Options extends ProviderOptions>(model: Model<Options>, patch: Partial<Model.Input>) {
     if (Object.keys(patch).length === 0) return model
     return Model.make<Options>({
       ...Model.input(model),
@@ -234,18 +232,15 @@ export namespace Model {
     readonly compatibility?: ModelCompatibility
   }
 
-  export type Input<Options extends ProviderOptions = ProviderOptions> = Omit<
-    ConstructorInput,
-    "id" | "provider" | "defaults" | "compatibility"
-  > & {
+  export type Input = Omit<ConstructorInput, "id" | "provider" | "defaults" | "compatibility"> & {
     readonly id: string | ModelID
     readonly provider: string | ProviderID
-    readonly defaults?: ModelDefaults.Input<Options>
+    readonly defaults?: ModelDefaults.Input
     readonly compatibility?: ModelCompatibility.Input
   }
 }
 
-export type ModelInput<Options extends ProviderOptions = ProviderOptions> = Model.Input<Options>
+export type ModelInput = Model.Input
 
 export type ModelProviderOptions<SelectedModel> = SelectedModel extends Model<infer Options> ? Options : never
 

+ 1 - 16
packages/ai/test/llm-option-types.types.ts

@@ -1,5 +1,5 @@
 import { Schema } from "effect"
-import { LLM, Model, type ModelProviderOptions, type ProviderOptions } from "../src"
+import { LLM, type Model, type ModelProviderOptions, type ProviderOptions } from "../src"
 import { OpenAIChat } from "../src/protocols"
 
 interface ExampleOptions {
@@ -45,18 +45,3 @@ LLM.request({ model: generic, prompt: "Hello", providerOptions: { arbitrary: { o
 
 const options: ModelProviderOptions<typeof model> = { example: { mode: "fast" } }
 void options
-
-model.route.model<ExampleProviderOptions>({
-  id: "example-with-defaults",
-  defaults: {
-    // @ts-expect-error Low-level model defaults preserve known provider option types.
-    providerOptions: { example: { mode: 1 } },
-  },
-})
-
-Model.update(model, {
-  defaults: {
-    // @ts-expect-error Updating a model cannot contradict its provider option type.
-    providerOptions: { example: { mode: "slow" } },
-  },
-})