Repository navigation
refactor(ai): tighten EvaluationRequest typing and deduplicate request normalization - #57601
Conversation
There was a problem hiding this comment.
Looks sound. Type checking for packages/ai, including the evaluation type tests in test/evaluation.types.ts, passes on both the base and this PR, and test/evaluation.test.ts passes. The per-model option types are still enforced after the covariance change, and passing EvaluationClient.evaluate straight to flatMap is fine. There's nothing to run, since runtime behaviour doesn't change.
Public API: only the experimental evaluation types in @opencode/ai change, and existing callers keep working. EvaluationRoute.evaluate changes from a function property to a method signature. EvaluationModel is now covariant in Options. The Model constraint on EvaluationRequestInput, request and run changes from object (plus a conditional check) to EvaluationModel. request gets a new EvaluationRequest | EvaluationRequestInput overload. Runtime behaviour, the CLI, the server, the SDK and config are untouched.
No concerns.
Problem
EvaluationModel<Options>was invariant inOptionsbecause_Optionsused(options: Options) => OptionsandEvaluationRoute.evaluateused a contravariant function property signature. As a result,EvaluationModel<SpecificOptions>was not assignable toEvaluationModel:EvaluationRequestInputhad to constrainModel extends objectwith a conditional intersection check (Model extends EvaluationModel<EvaluationModelOptions<Model>> ? unknown : never).request()had to castinput.model as unknown as EvaluationModel.run()had to duplicateinput instanceof EvaluationRequest ? input : request(input)and castrequest as EvaluationRequestFor<EvaluationOptions, EvaluationQuestions>.Change
Make
EvaluationModel<Options>covariant inOptions(matchingLanguageModelandMediaModel) and allowrequest()to acceptEvaluationRequest | EvaluationRequestInputdirectly sorun()delegates normalization torequest(input)without casts.export interface EvaluationRoute<Options extends EvaluationOptions = EvaluationOptions> { readonly id: string - readonly evaluate: ( - request: EvaluationRequestFor<Options>, - execute: Execute, - ) => Effect.Effect<EvaluationResponse, AIError> + evaluate(request: EvaluationRequestFor<Options>, execute: Execute): Effect.Effect<EvaluationResponse, AIError> } export class EvaluationModel<Options extends EvaluationOptions = EvaluationOptions> { - declare protected readonly _Options: (options: Options) => Options + declare protected readonly _Options: OptionsOut of scope