(opts: {
spec?: GatewaySpec;
name?: string;
baseUrl?: string;
apiKeyEnv?: string;
modelId?: string;
contextWindow?: number;
toolCalls?: boolean;
})
| 192 | * |
| 193 | * The base URL must be the root (e.g. `https://integrate.api.nvidia.com/v1`). Users very |
| 194 | * commonly paste a deeper path instead — the model-list URL (`…/v1/models`) or the full |
| 195 | * chat URL (`…/v1/chat/completions`) — and then EVERY request hits `…/v1/models/chat/completions` |
| 196 | * (a 404) or `…/v1/chat/completions/chat/completions`. We defensively strip those trailing |
| 197 | * segments and any trailing slash so the common copy-paste mistake just works. |
| 198 | */ |
| 199 | export function normalizeBaseUrl(raw: string): string { |
| 200 | let u = (raw ?? '').trim().replace(/\/+$/, ''); // drop trailing slash(es) |
| 201 | u = u.replace(/\/(?:chat\/completions|completions|models)$/i, ''); // strip a pasted endpoint path |
| 202 | return u; |
| 203 | } |
| 204 | |
| 205 | export function buildCustomEntry(opts: { |
| 206 | spec?: GatewaySpec; |
| 207 | name?: string; |
| 208 | baseUrl?: string; |
| 209 | apiKeyEnv?: string; |
| 210 | modelId?: string; |
| 211 | contextWindow?: number; |
| 212 | toolCalls?: boolean; |
| 213 | }): CustomProviderEntry { |
| 214 | // spec names are already valid; a user-supplied custom name may be a raw URL → slugify it. |
| 215 | const name = opts.spec ? (opts.spec.name ?? '').trim() : slugifyProviderName(opts.name ?? ''); |
| 216 | const baseUrl = normalizeBaseUrl(opts.baseUrl ?? opts.spec?.baseUrl ?? ''); |
| 217 | const apiKeyEnv = (opts.apiKeyEnv ?? opts.spec?.apiKeyEnv ?? '').trim(); |
| 218 | if (!name) throw new Error('provider name is required'); |
| 219 | if (/[\s/:]/.test(name)) throw new Error(`invalid provider name "${name}": must not contain spaces, "/", or ":"`); |
| 220 | if (!baseUrl) throw new Error('baseUrl is required'); |
| 221 | if (!apiKeyEnv) throw new Error('apiKeyEnv is required'); |
| 222 | |
| 223 | const entry: CustomProviderEntry = { name, apiKeyEnv, baseUrl }; |
| 224 | const modelId = opts.modelId ?? opts.spec?.suggestedModel; |
| 225 | if (modelId) { |
no test coverage detected