|
10 | 10 |
|
11 | 11 | from .config import get_prompt_manager |
12 | 12 | from .http import build_cors_headers |
| 13 | +from .instance_service import build_instance_service |
13 | 14 | from .routes_openai import openai_bp |
14 | 15 | from .routes_ollama import ollama_bp |
15 | 16 | from .websocket_routes import register_websocket_routes |
@@ -49,6 +50,7 @@ def create_app( |
49 | 50 | DEFAULT_WEB_SEARCH=bool(default_web_search), |
50 | 51 | INJECT_DEFAULT_INSTRUCTIONS=bool(inject_default_instructions), |
51 | 52 | PROMPT_MANAGER=prompt_manager, |
| 53 | + INSTANCE_SERVICE=None, |
52 | 54 | ADMIN_TOKEN=( |
53 | 55 | admin_token |
54 | 56 | if isinstance(admin_token, str) and admin_token |
@@ -107,6 +109,16 @@ def _is_in_trusted_ranges(value: str | None) -> bool: |
107 | 109 | return jsonify({"error": {"message": "Invalid admin token"}}), 403 |
108 | 110 | return None |
109 | 111 |
|
| 112 | + def _get_instance_service(): |
| 113 | + service = app.config.get("INSTANCE_SERVICE") |
| 114 | + if service is None: |
| 115 | + service = build_instance_service() |
| 116 | + app.config["INSTANCE_SERVICE"] = service |
| 117 | + return service |
| 118 | + |
| 119 | + def _registry_error(exc: Exception): |
| 120 | + return jsonify({"error": {"message": str(exc)}}), 400 |
| 121 | + |
110 | 122 | @app.get("/admin/prompts") |
111 | 123 | def admin_prompts_state(): |
112 | 124 | denied = _require_local_admin() |
@@ -142,6 +154,43 @@ def admin_prompts_config(): |
142 | 154 | return jsonify({"error": {"message": str(exc)}}), 400 |
143 | 155 | return jsonify(prompt_manager.as_dict()) |
144 | 156 |
|
| 157 | + @app.get("/admin/profiles") |
| 158 | + def admin_profiles(): |
| 159 | + denied = _require_local_admin() |
| 160 | + if denied is not None: |
| 161 | + return denied |
| 162 | + try: |
| 163 | + service = _get_instance_service() |
| 164 | + except (FileNotFoundError, OSError, ValueError) as exc: |
| 165 | + return _registry_error(exc) |
| 166 | + return jsonify({"profiles": service.list_profiles()}) |
| 167 | + |
| 168 | + @app.get("/admin/instances") |
| 169 | + def admin_instances(): |
| 170 | + denied = _require_local_admin() |
| 171 | + if denied is not None: |
| 172 | + return denied |
| 173 | + try: |
| 174 | + service = _get_instance_service() |
| 175 | + except (FileNotFoundError, OSError, ValueError) as exc: |
| 176 | + return _registry_error(exc) |
| 177 | + return jsonify({"instances": service.list_instances()}) |
| 178 | + |
| 179 | + @app.get("/admin/instances/<instance_id>/preview") |
| 180 | + def admin_instance_preview(instance_id: str): |
| 181 | + denied = _require_local_admin() |
| 182 | + if denied is not None: |
| 183 | + return denied |
| 184 | + try: |
| 185 | + service = _get_instance_service() |
| 186 | + except (FileNotFoundError, OSError, ValueError) as exc: |
| 187 | + return _registry_error(exc) |
| 188 | + try: |
| 189 | + preview = service.render_instance_preview(instance_id) |
| 190 | + except ValueError as exc: |
| 191 | + return jsonify({"error": {"message": str(exc)}}), 404 |
| 192 | + return jsonify(preview) |
| 193 | + |
145 | 194 | @app.after_request |
146 | 195 | def _cors(resp): |
147 | 196 | for k, v in build_cors_headers().items(): |
|
0 commit comments