()
| 44 | } |
| 45 | |
| 46 | async listModels(): Promise<ModelInfo[]> { |
| 47 | if (!this.customApiKey) return []; |
| 48 | if (this.explicitModels) return this.explicitModels; |
| 49 | if (this.discovered) return this.discovered; |
| 50 | |
| 51 | // Auto-discovery: ask the gateway what it serves. |
| 52 | try { |
| 53 | const res = await fetch(modelsEndpoint(this.discoverBaseUrl), { |
| 54 | headers: { Authorization: `Bearer ${this.customApiKey}`, ...(this.customHeaders ?? {}) }, |
| 55 | signal: AbortSignal.timeout(8000), |
| 56 | }); |
| 57 | if (!res.ok) { |
| 58 | logger.warn(`Custom provider ${this.name}: GET /models returned ${res.status}; no models discovered. ` + |
| 59 | `List them explicitly under providers.custom[].models if discovery isn't supported.`); |
| 60 | this.discovered = []; |
| 61 | return this.discovered; |
| 62 | } |
| 63 | const body = await res.json(); |
| 64 | const models = mapDiscoveredModels(body); |
| 65 | if (models.length === 0) { |
| 66 | logger.warn(`Custom provider ${this.name}: /models returned no usable ids.`); |
| 67 | } else { |
| 68 | logger.info(`Custom provider ${this.name}: discovered ${models.length} models from /models.`); |
| 69 | } |
| 70 | this.discovered = models; |
| 71 | return models; |
| 72 | } catch (e: any) { |
| 73 | logger.warn(`Custom provider ${this.name}: model discovery failed (${e?.message ?? e}). ` + |
| 74 | `Set providers.custom[].models explicitly to use it offline-of-discovery.`); |
| 75 | this.discovered = []; |
| 76 | return this.discovered; |
| 77 | } |
| 78 | } |
| 79 | } |
no test coverage detected