refactor(ai): rename decision imageInput to mediaInput (#58879)

This commit is contained in:
Aiden Cline
2026-10-25 23:42:29 -05:00
committed by GitHub
Unverified
parent e928d4ffa1
commit ab0b0129f9
5 changed files with 16 additions and 15 deletions
+4 -3
View File
@@ -155,10 +155,11 @@ export interface DecisionModelRoute<Options extends DecisionOptions = DecisionOp
export class DecisionModelCompatibility extends Schema.Class<DecisionModelCompatibility>("Decision.ModelCompatibility")(
{
/**
* Where a System One host reads media, from models.dev `[api.systemone] compatibility.image_input`:
* `assets` (TypeSafe's assets map), `images` (top-level lists) or `state` (items inside a state list).
* Where a System One host reads media, from models.dev `[api.systemone] compatibility.media_input`, named after
* where the media goes in the body: `assets` (TypeSafe's assets map, referenced from the state), `state` (items
* inside a state list) or `root` (one top-level list per kind: `images`, `audio`, `videos`).
*/
imageInput: Schema.optional(Schema.Literals(["assets", "images", "state"])),
mediaInput: Schema.optional(Schema.Literals(["assets", "state", "root"])),
},
) {}
@@ -27,7 +27,7 @@ export const protocol = DecisionRoute.protocol({
inlineMedia: true,
body: {
from: (request) =>
SystemOne.encodeBody(request, "images").pipe(Effect.map((input) => ({ model: request.model.id, input }))),
SystemOne.encodeBody(request, "root").pipe(Effect.map((input) => ({ model: request.model.id, input }))),
},
response: {
decode: (response, context) =>
+9 -9
View File
@@ -19,8 +19,8 @@ export const DEFAULT_PATH = "/systemone"
export const DEFAULT_BASE_URL = "https://api.typesafe.ai/v1"
/** `messages` is Baseten's own placement (parts in a user message inside `state.messages`), set by its provider. */
type ImageInput = NonNullable<DecisionModelCompatibility["imageInput"]> | "messages"
/** `state.messages` is Baseten's own placement (parts in a user message inside `state.messages`), set by its provider. */
type MediaInput = NonNullable<DecisionModelCompatibility["mediaInput"]> | "state.messages"
const Probability = Schema.Number.check(Schema.isBetween({ minimum: 0, maximum: 1 }))
const Answer = Schema.Union([
@@ -58,13 +58,13 @@ export type Response = Schema.Schema.Type<typeof Response>
const ID = "system-one"
const NAME = "System One"
/** The System One body without `model`; media goes where the model's `imageInput` says, else `fallback`. */
/** The System One body without `model`; media goes where the model's `mediaInput` says, else `fallback`. */
export const encodeBody = Effect.fn("SystemOne.encodeBody")(function* (
request: DecisionRequestFor,
fallback: ImageInput,
fallback: MediaInput,
) {
const questions = yield* encodeQuestions(request.questions)
const placed = yield* placeMedia(request, request.model.compatibility?.imageInput ?? fallback)
const placed = yield* placeMedia(request, request.model.compatibility?.mediaInput ?? fallback)
return { ...mergeJsonRecords(request.providerOptions, request.http?.body), ...placed, questions }
})
@@ -103,7 +103,7 @@ const encodeQuestions = (questions: ReadonlyArray<DecisionQuestion>) =>
] as const)
}).pipe(Effect.map(Object.fromEntries))
const placeMedia = Effect.fnUntraced(function* (request: DecisionRequestFor, imageInput: ImageInput) {
const placeMedia = Effect.fnUntraced(function* (request: DecisionRequestFor, mediaInput: MediaInput) {
const parts = request.input
const unsupported = (asset: Media.Asset, accepted: string) =>
new AIError({
@@ -116,9 +116,9 @@ const placeMedia = Effect.fnUntraced(function* (request: DecisionRequestFor, ima
})
const media = parts.flatMap((part) => (part.type === "media" ? [part.media] : []))
if (media.length === 0) return { state: state(parts.map(plain)) }
if (imageInput === "state") return { state: yield* Effect.forEach(parts, (part) => stateItem(part, unsupported)) }
if (mediaInput === "state") return { state: yield* Effect.forEach(parts, (part) => stateItem(part, unsupported)) }
// Chat-style content in one user message: text and JSON as text parts, media as in `state`.
if (imageInput === "messages")
if (mediaInput === "state.messages")
return {
state: {
messages: [
@@ -133,7 +133,7 @@ const placeMedia = Effect.fnUntraced(function* (request: DecisionRequestFor, ima
],
},
}
if (imageInput === "images") {
if (mediaInput === "root") {
const lists = { image: "images", audio: "audio", video: "videos" } as const
const unplaced = media.find((asset) => !Object.hasOwn(lists, asset.kind))
if (unplaced !== undefined) return yield* unsupported(unplaced, "images, audio and video")
+1 -1
View File
@@ -47,7 +47,7 @@ const decisionProtocol = DecisionRoute.protocol({
id: "baseten-system-one",
body: {
from: (request) =>
SystemOne.encodeBody(request, "messages").pipe(Effect.map((body) => ({ ...body, model: request.model.id }))),
SystemOne.encodeBody(request, "state.messages").pipe(Effect.map((body) => ({ ...body, model: request.model.id }))),
},
})
+1 -1
View File
@@ -203,7 +203,7 @@ export const configure = (input: LanguageModelOptions = {}) => {
http: input.http,
})
const decision = (modelID: string | ModelID) =>
decisionRoute.model<OpenRouterDecisionOptions>({ id: modelID, compatibility: { imageInput: "state" } })
decisionRoute.model<OpenRouterDecisionOptions>({ id: modelID, compatibility: { mediaInput: "state" } })
return {
id,
model: (modelID: string | ModelID) =>