(model: VercelModel, existing: ExistingModel | undefined)
| 80 | } satisfies SyncProvider<VercelModel>; |
| 81 | |
| 82 | export function buildVercelModel(model: VercelModel, existing: ExistingModel | undefined): SyncedModel { |
| 83 | const tags = new Set(model.tags); |
| 84 | const releaseDate = model.released |
| 85 | ? dateFromTimestamp(model.released) |
| 86 | : existing?.release_date ?? new Date().toISOString().slice(0, 10); |
| 87 | const context = model.context_window > 0 |
| 88 | ? model.context_window |
| 89 | : existing?.limit?.context ?? 0; |
| 90 | const output = model.max_tokens > 0 |
| 91 | ? model.max_tokens |
| 92 | : existing?.limit?.output ?? 0; |
| 93 | const input = model.id.startsWith("openai/") && context > output |
| 94 | ? context - output |
| 95 | : undefined; |
| 96 | const cost = buildCost(model.pricing, existing?.cost); |
| 97 | |
| 98 | const synced: SyncedFullModel = { |
| 99 | name: existing?.name ?? model.name, |
| 100 | description: existing?.description ?? describeModel({ |
| 101 | id: model.id, |
| 102 | name: existing?.name ?? model.name, |
| 103 | family: existing?.family ?? inferFamily(model.id, model.name), |
| 104 | reasoning: existing?.reasoning ?? tags.has("reasoning"), |
| 105 | tool_call: model.type === "language" |
| 106 | ? existing?.tool_call ?? tags.has("tool-use") |
| 107 | : tags.has("tool-use"), |
| 108 | structured_output: existing?.structured_output, |
| 109 | open_weights: existing?.open_weights ?? false, |
| 110 | limit: { context, input, output }, |
| 111 | modalities: { |
| 112 | input: model.type === "transcription" |
| 113 | ? ["audio"] |
| 114 | : model.type === "realtime" |
| 115 | ? ["text", "audio"] |
| 116 | : ["text", tags.has("vision") ? "image" : undefined, tags.has("file-input") ? "pdf" : undefined] |
| 117 | .filter((value): value is "text" | "image" | "pdf" => value !== undefined), |
| 118 | output: model.type === "speech" |
| 119 | ? ["audio"] |
| 120 | : model.type === "realtime" |
| 121 | ? ["text", "audio"] |
| 122 | : model.type === "image" |
| 123 | ? ["image"] |
| 124 | : model.type === "video" |
| 125 | ? ["video"] |
| 126 | : tags.has("image-generation") |
| 127 | ? ["text", "image"] |
| 128 | : ["text"], |
| 129 | }, |
| 130 | }), |
| 131 | family: existing?.family ?? inferFamily(model.id, model.name), |
| 132 | release_date: releaseDate, |
| 133 | last_updated: existing?.last_updated ?? releaseDate, |
| 134 | attachment: existing?.attachment ?? (tags.has("vision") || tags.has("file-input")), |
| 135 | reasoning: existing?.reasoning ?? tags.has("reasoning"), |
| 136 | reasoning_options: existing?.reasoning_options, |
| 137 | temperature: true, |
| 138 | tool_call: model.type === "language" |
| 139 | ? existing?.tool_call ?? tags.has("tool-use") |
no test coverage detected