OpenAI-compatible /v1/models
(endpoint: AIEndpoint)
| 114 | |
| 115 | /** OpenAI-compatible /v1/models */ |
| 116 | async function fetchOpenAIModels(endpoint: AIEndpoint): Promise<string[]> { |
| 117 | const requestUrl = buildProviderModelsUrl( |
| 118 | endpoint.provider, |
| 119 | endpoint.baseUrl, |
| 120 | endpoint.apiKey, |
| 121 | endpoint.useExactRequestUrl, |
| 122 | ); |
| 123 | if (!requestUrl) return []; |
| 124 | logAIEndpointDebug("request", endpoint, { |
| 125 | action: "fetch-models", |
| 126 | method: "GET", |
| 127 | requestUrl, |
| 128 | }); |
| 129 | // 使用跨域适配fetch,和AI对话逻辑一致 |
| 130 | const endpointFetch = getEndpointFetch(endpoint); |
| 131 | const response = await endpointFetch(requestUrl, { |
| 132 | headers: { Authorization: `Bearer ${endpoint.apiKey}` }, |
| 133 | }); |
| 134 | if (!response.ok) { |
| 135 | const errorBody = await response.text(); |
| 136 | logAIEndpointDebug("error", endpoint, { |
| 137 | action: "fetch-models", |
| 138 | method: "GET", |
| 139 | requestUrl, |
| 140 | status: response.status, |
| 141 | statusText: response.statusText, |
| 142 | contentType: response.headers.get("content-type"), |
| 143 | responseLength: errorBody.length, |
| 144 | responseBodyPreview: summarizeDebugText(errorBody), |
| 145 | }); |
| 146 | throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`); |
| 147 | } |
| 148 | const rawBody = await response.text(); |
| 149 | let data: { data?: Array<{ id: string }> }; |
| 150 | |
| 151 | try { |
| 152 | data = JSON.parse(rawBody); |
| 153 | } catch { |
| 154 | const contentType = response.headers.get("content-type") || ""; |
| 155 | logAIEndpointDebug("error", endpoint, { |
| 156 | action: "fetch-models", |
| 157 | method: "GET", |
| 158 | requestUrl, |
| 159 | status: response.status, |
| 160 | statusText: response.statusText, |
| 161 | contentType, |
| 162 | responseLength: rawBody.length, |
| 163 | responseBodyPreview: summarizeDebugText(rawBody), |
| 164 | }); |
| 165 | const lookedLikeHtml = /^\s*<(!doctype|html)/i.test(rawBody) || contentType.includes("html"); |
| 166 | throw new Error( |
| 167 | lookedLikeHtml |
| 168 | ? "The endpoint returned an HTML page instead of JSON. Make sure the base URL starts with http:// or https:// and points to the API root, not a console/dashboard page." |
| 169 | : "The endpoint did not return JSON. Make sure the base URL starts with http:// or https:// and points to the API root, not a console page.", |
| 170 | ); |
| 171 | } |
| 172 | |
| 173 | if (!Array.isArray(data.data)) { |
no test coverage detected