From f4723cd083114dbe4dba5ed6eae7883ac8bd1dd1 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Tue, 3 Mar 2026 22:47:36 +0800 Subject: [PATCH] docs: restructure LLM model configs API documentation for nested config object Update API documentation to reflect new nested `config` object structure in LLM model configurations endpoints. The response format now encapsulates provider-specific fields (provider, base_url, model, temperature, api_key, max_tokens) within a `config` object, while moving ownership metadata (user_id, group_id, is_default, version, created_at, updated_at) to the top level. This aligns the user-facing endpoints with the group configuration structure and improves API consistency. --- docs/llm-model-configs-api.md | 86 ++++++++++++------- .../db/repositories/llm_model_configs.py | 22 +++-- .../schemas/controller/llm_model_configs.py | 18 ++-- 3 files changed, 80 insertions(+), 46 deletions(-) diff --git a/docs/llm-model-configs-api.md b/docs/llm-model-configs-api.md index 01f97c6f8..e61613b60 100644 --- a/docs/llm-model-configs-api.md +++ b/docs/llm-model-configs-api.md @@ -192,15 +192,15 @@ The `model_type` field accepts the following values: | `config_id` | UUID | Configuration ID | | `name` | string | Configuration name | | `model_type` | string | Model type | +| `config` | LLMModelConfigData | Configuration data (provider, base_url, model, temperature, etc.) | +| `user_id` | UUID (nullable) | Owner user ID | +| `group_id` | UUID (nullable) | Owner group ID | +| `is_default` | boolean | Default flag | +| `version` | integer | Optimistic locking version | +| `created_at` | TIMESTAMP | Creation time | +| `updated_at` | TIMESTAMP | Last update time | | `source` | string | Source: "user" or "group" | | `group_name` | string (nullable) | Group name if source is "group" | -| `is_default` | boolean | Default flag | -| `provider` | string | LLM provider | -| `base_url` | string | API base URL | -| `model` | string | Model name | -| `temperature` | float | Temperature | -| `api_key` | string (nullable) | API key | -| `max_tokens` | integer (nullable) | Max tokens | --- @@ -279,37 +279,55 @@ curl -X GET http://localhost:3080/v3/access/users/{user_id}/llm-model-configs \ "config_id": "uuid-1", "name": "GPT-4", "model_type": "text", - "source": "user", - "group_name": null, + "config": { + "provider": "openai", + "base_url": "https://api.openai.com/v1", + "model": "gpt-4", + "temperature": 0.7, + "api_key": "sk-xxx" + }, + "user_id": "uuid-user", + "group_id": null, "is_default": true, - "provider": "openai", - "model": "gpt-4", - "base_url": "https://api.openai.com/v1", - "temperature": 0.7, - "api_key": "sk-xxx" + "version": 0, + "created_at": "2026-03-03T14:32:48.158880Z", + "updated_at": "2026-03-03T14:32:48.158880Z", + "source": "user", + "group_name": null }, { "config_id": "uuid-2", "name": "Claude-3", "model_type": "text", - "source": "group", - "group_name": "Developers", + "config": { + "provider": "anthropic", + "base_url": "https://api.anthropic.com", + "model": "claude-3-opus-20240229", + "temperature": 0.7, + "api_key": null + }, + "user_id": null, + "group_id": "uuid-group", "is_default": true, - "provider": "anthropic", - "model": "claude-3-opus-20240229", - "base_url": "https://api.anthropic.com", - "temperature": 0.7, - "api_key": null + "version": 0, + "created_at": "2026-03-03T14:32:48.158880Z", + "updated_at": "2026-03-03T14:32:48.158880Z", + "source": "group", + "group_name": "Developers" } ], "default_config": { "config_id": "uuid-1", "name": "GPT-4", "model_type": "text", - "source": "user", - "group_name": null, + "config": { + "provider": "openai", + ... + }, + "user_id": "uuid-user", + "group_id": null, "is_default": true, - "provider": "openai", + "version": 0, ... }, "total": 2 @@ -317,10 +335,11 @@ curl -X GET http://localhost:3080/v3/access/users/{user_id}/llm-model-configs \ ``` **Note:** -- User's own config shows `api_key: "sk-xxx"` (visible to owner) -- Inherited group config shows `api_key: null` (hidden from users) +- User's own config shows `config.api_key: "sk-xxx"` (visible to owner) +- Inherited group config shows `config.api_key: null` (hidden from users) - `source: "user"` indicates the config belongs to the user - `source: "group"` indicates the config is inherited from a group +- Configuration fields are nested in the `config` object (same structure as group endpoints) ### 4. Get group configurations @@ -598,13 +617,19 @@ The API implements strict API key visibility controls to protect sensitive crede "configs": [ { "config_id": "uuid-1", + "name": "GPT-4", "source": "user", - "api_key": "sk-xxx" // Visible (own config) + "config": { + "api_key": "sk-xxx" // Visible (own config) + } }, { "config_id": "uuid-2", + "name": "Claude-3", "source": "group", - "api_key": null // Hidden (inherited from group) + "config": { + "api_key": null // Hidden (inherited from group) + } } ] } @@ -614,8 +639,11 @@ The API implements strict API key visibility controls to protect sensitive crede "configs": [ { "config_id": "uuid-1", + "name": "GPT-4", "source": "user", - "api_key": null // Hidden (another user's config) + "config": { + "api_key": null // Hidden (another user's config) + } } ] } diff --git a/gns3server/db/repositories/llm_model_configs.py b/gns3server/db/repositories/llm_model_configs.py index 3517f6b52..3d7cbe818 100644 --- a/gns3server/db/repositories/llm_model_configs.py +++ b/gns3server/db/repositories/llm_model_configs.py @@ -465,10 +465,15 @@ class LLMModelConfigsRepository(BaseRepository): "config_id": config.config_id, "name": config.name, "model_type": config.model_type, - "source": "user", - "group_name": None, + "config": config_dict, + "user_id": config.user_id, + "group_id": config.group_id, "is_default": config.is_default, - **config_dict + "version": config.version, + "created_at": config.created_at, + "updated_at": config.updated_at, + "source": "user", + "group_name": None }) if config.is_default and default_config is None: @@ -487,10 +492,15 @@ class LLMModelConfigsRepository(BaseRepository): "config_id": config.config_id, "name": config.name, "model_type": config.model_type, - "source": "group", - "group_name": group_names_map[group_id], + "config": config_dict, + "user_id": config.user_id, + "group_id": config.group_id, "is_default": config.is_default, - **config_dict + "version": config.version, + "created_at": config.created_at, + "updated_at": config.updated_at, + "source": "group", + "group_name": group_names_map[group_id] }) if config.is_default and default_config is None: diff --git a/gns3server/schemas/controller/llm_model_configs.py b/gns3server/schemas/controller/llm_model_configs.py index 662cbbb25..9b70f3ec6 100644 --- a/gns3server/schemas/controller/llm_model_configs.py +++ b/gns3server/schemas/controller/llm_model_configs.py @@ -99,25 +99,21 @@ class LLMModelConfigResponse(DateTimeModelMixin): model_config = ConfigDict(from_attributes=True) -class LLMModelConfigWithSource(BaseModel): +class LLMModelConfigWithSource(DateTimeModelMixin): """Model configuration with source information (for inheritance).""" config_id: UUID name: str model_type: ModelType + config: LLMModelConfigData + user_id: Optional[UUID] = None + group_id: Optional[UUID] = None + is_default: bool + version: int source: str = Field(..., description="Source: 'user' or 'group'") group_name: Optional[str] = Field(None, description="Group name if source is 'group'") - is_default: bool - # Config fields - provider: str - base_url: str - model: str - temperature: float - api_key: Optional[str] = None - max_tokens: Optional[int] = None - # Allow extra config fields - model_config = ConfigDict(extra="allow") + model_config = ConfigDict(from_attributes=True, extra="allow") class LLMModelConfigInheritedResponse(BaseModel):