Fetch available Anthropic models using a provided API key file path and/or custom API URL. Used by the preferences refresh button to load models before saving.
()
| 444 | ) |
| 445 | @pga_login_required |
| 446 | def refresh_anthropic_models(): |
| 447 | """ |
| 448 | Fetch available Anthropic models using a provided API key file path |
| 449 | and/or custom API URL. |
| 450 | Used by the preferences refresh button to load models before saving. |
| 451 | """ |
| 452 | from pgadmin.llm.utils import ( |
| 453 | read_api_key_file, validate_api_key_path, validate_api_url |
| 454 | ) |
| 455 | |
| 456 | data = request.get_json(force=True, silent=True) or {} |
| 457 | api_key_file = data.get('api_key_file', '') |
| 458 | api_url = data.get('api_url', '') |
| 459 | |
| 460 | if api_url and not validate_api_url(api_url): |
| 461 | return make_json_response( |
| 462 | data={'models': [], |
| 463 | 'error': 'API URL is not in the allowed list. ' |
| 464 | 'Contact your administrator to update ' |
| 465 | 'ALLOWED_LLM_API_URLS in the server ' |
| 466 | 'configuration.'}, |
| 467 | status=200 |
| 468 | ) |
| 469 | |
| 470 | api_key = None |
| 471 | if api_key_file: |
| 472 | # Capture the resolved canonical path and pass it forward so |
| 473 | # the file we open is the one we just validated (avoids a |
| 474 | # symlink-swap TOCTOU between validation and read). |
| 475 | safe_path = validate_api_key_path(api_key_file) |
| 476 | if safe_path is None: |
| 477 | return make_json_response( |
| 478 | data={'models': [], |
| 479 | 'error': 'API key file path is not permitted. ' |
| 480 | 'The file must be within your private ' |
| 481 | 'user storage directory; shared storage ' |
| 482 | 'and other locations are not allowed for ' |
| 483 | 'security reasons.'}, |
| 484 | status=200 |
| 485 | ) |
| 486 | api_key = read_api_key_file(safe_path) |
| 487 | |
| 488 | if not api_key and not api_url: |
| 489 | return make_json_response( |
| 490 | data={'models': [], |
| 491 | 'error': 'No API key or custom URL provided'}, |
| 492 | status=200 |
| 493 | ) |
| 494 | |
| 495 | try: |
| 496 | models = _fetch_anthropic_models(api_key, api_url) |
| 497 | return make_json_response(data={'models': models}, status=200) |
| 498 | except LLMApiError as e: |
| 499 | return make_json_response( |
| 500 | data={'models': [], 'error': str(e)}, |
| 501 | status=200 |
| 502 | ) |
| 503 | except Exception: |
nothing calls this directly
no test coverage detected