Make an HTTP request to the Docker Model Runner API.
(self, payload: dict)
| 220 | ] |
| 221 | |
| 222 | def _make_request(self, payload: dict) -> dict: |
| 223 | """Make an HTTP request to the Docker Model Runner API.""" |
| 224 | headers = { |
| 225 | 'Content-Type': 'application/json' |
| 226 | } |
| 227 | |
| 228 | # Docker Model Runner uses /engines/v1 path for OpenAI-compatible API |
| 229 | url = f'{self._api_url}/engines/v1/chat/completions' |
| 230 | |
| 231 | request = urllib.request.Request( |
| 232 | url, |
| 233 | data=json.dumps(payload).encode('utf-8'), |
| 234 | headers=headers, |
| 235 | method='POST' |
| 236 | ) |
| 237 | |
| 238 | try: |
| 239 | # Use longer timeout for local models which can be slower |
| 240 | with urllib.request.urlopen( |
| 241 | request, timeout=300, context=SSL_CONTEXT |
| 242 | ) as response: |
| 243 | return json.loads(response.read().decode('utf-8')) |
| 244 | except urllib.error.HTTPError as e: |
| 245 | error_body = e.read().decode('utf-8') |
| 246 | try: |
| 247 | error_data = json.loads(error_body) |
| 248 | error_msg = error_data.get('error', {}).get('message', str(e)) |
| 249 | except json.JSONDecodeError: |
| 250 | error_msg = error_body or str(e) |
| 251 | |
| 252 | raise LLMClientError(LLMError( |
| 253 | message=error_msg, |
| 254 | code=str(e.code), |
| 255 | provider=self.provider_name, |
| 256 | retryable=e.code in (429, 500, 502, 503, 504) |
| 257 | )) |
| 258 | except urllib.error.URLError as e: |
| 259 | raise LLMClientError(LLMError( |
| 260 | message=f"Connection error: {e.reason}. " |
| 261 | f"Is Docker Model Runner running at {self._api_url}?", |
| 262 | provider=self.provider_name, |
| 263 | retryable=True |
| 264 | )) |
| 265 | except socket.timeout: |
| 266 | raise LLMClientError(LLMError( |
| 267 | message="Request timed out. Local models can be slow - " |
| 268 | "try a smaller model or wait for the response.", |
| 269 | code='timeout', |
| 270 | provider=self.provider_name, |
| 271 | retryable=True |
| 272 | )) |
| 273 | |
| 274 | def _parse_response(self, data: dict) -> LLMResponse: |
| 275 | """Parse the API response into an LLMResponse.""" |
no test coverage detected