feat(settings): add model provider management with full CRUD support

Add a new settings page for managing API model providers (name, API URL,
API key, applicable agent types). Includes database migration, SeaORM
entity, backend CRUD commands/handlers, frontend settings UI with agent
type filter, add/edit/delete dialogs, and i18n support for all 10 locales.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-05 16:35:14 +08:00
parent 6359651247
commit ba19299696
32 changed files with 1501 additions and 11 deletions

View File

@@ -7,6 +7,7 @@ pub mod folder_commands;
pub mod folders;
pub mod git;
pub mod mcp;
pub mod model_provider;
pub mod project_boot;
pub mod system_settings;
pub mod terminal;

View File

@@ -0,0 +1,88 @@
use std::sync::Arc;
use axum::{extract::Extension, Json};
use serde::Deserialize;
use crate::app_error::AppCommandError;
use crate::app_state::AppState;
use crate::commands::model_provider as mp_commands;
use crate::models::model_provider::ModelProviderInfo;
// ---------------------------------------------------------------------------
// Param structs
// ---------------------------------------------------------------------------
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateModelProviderParams {
pub name: String,
pub api_url: String,
pub api_key: String,
pub agent_types: Vec<String>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateModelProviderParams {
pub id: i32,
pub name: Option<String>,
pub api_url: Option<String>,
pub api_key: Option<String>,
pub agent_types: Option<Vec<String>>,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ModelProviderIdParams {
pub id: i32,
}
// ---------------------------------------------------------------------------
// Handlers
// ---------------------------------------------------------------------------
pub async fn list_model_providers(
Extension(state): Extension<Arc<AppState>>,
) -> Result<Json<Vec<ModelProviderInfo>>, AppCommandError> {
let result = mp_commands::list_model_providers_core(&state.db).await?;
Ok(Json(result))
}
pub async fn create_model_provider(
Extension(state): Extension<Arc<AppState>>,
Json(params): Json<CreateModelProviderParams>,
) -> Result<Json<ModelProviderInfo>, AppCommandError> {
let result = mp_commands::create_model_provider_core(
&state.db,
params.name,
params.api_url,
params.api_key,
params.agent_types,
)
.await?;
Ok(Json(result))
}
pub async fn update_model_provider(
Extension(state): Extension<Arc<AppState>>,
Json(params): Json<UpdateModelProviderParams>,
) -> Result<Json<ModelProviderInfo>, AppCommandError> {
let result = mp_commands::update_model_provider_core(
&state.db,
params.id,
params.name,
params.api_url,
params.api_key,
params.agent_types,
)
.await?;
Ok(Json(result))
}
pub async fn delete_model_provider(
Extension(state): Extension<Arc<AppState>>,
Json(params): Json<ModelProviderIdParams>,
) -> Result<Json<()>, AppCommandError> {
mp_commands::delete_model_provider_core(&state.db, params.id).await?;
Ok(Json(()))
}

View File

@@ -202,6 +202,11 @@ pub fn build_router(state: Arc<AppState>, token: String, static_dir: std::path::
.route("/set_chat_message_language", post(handlers::chat_channel::set_chat_message_language))
.route("/weixin_get_qrcode", post(handlers::chat_channel::weixin_get_qrcode))
.route("/weixin_check_qrcode", post(handlers::chat_channel::weixin_check_qrcode))
// ─── Model Providers ───
.route("/list_model_providers", post(handlers::model_provider::list_model_providers))
.route("/create_model_provider", post(handlers::model_provider::create_model_provider))
.route("/update_model_provider", post(handlers::model_provider::update_model_provider))
.route("/delete_model_provider", post(handlers::model_provider::delete_model_provider))
// ─── Terminal ───
.route("/terminal_spawn", post(handlers::terminal::terminal_spawn))
.route("/terminal_write", post(handlers::terminal::terminal_write))