gitdataai/libs/agent/model/provider.rs
ZhenYi 10c0cc007b refactor(agent): split into submodules and add Qdrant embedding
- Split agent crate into client/, model/, agent/ subdirs
- Add billing.rs for token usage recording
- Add sync.rs for upstream model sync
- EmbedService: Qdrant-backed vector memory for semantic search
- ChatService: wire EmbedService for memory lookup, passive skill awareness
- ReAct loop: streamline with tokio::select! and proper error handling
2026-04-25 20:09:33 +08:00

124 lines
3.7 KiB
Rust

//! AI provider management — CRUD for model providers.
//!
//! All functions take `&DatabaseConnection` instead of `&AppService`
//! so they can live in the agent crate.
use chrono::Utc;
use db::database::AppDatabase;
use models::agents::model_provider;
use models::agents::{ModelStatus, model_provider::Entity as ProviderEntity};
use sea_orm::*;
use uuid::Uuid;
use crate::error::AgentError;
#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct CreateProviderRequest {
pub name: String,
pub display_name: String,
pub website: Option<String>,
}
#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
pub struct UpdateProviderRequest {
pub display_name: Option<String>,
pub website: Option<String>,
pub status: Option<String>,
}
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
pub struct ProviderResponse {
pub id: Uuid,
pub name: String,
pub display_name: String,
pub website: Option<String>,
pub status: String,
pub created_at: chrono::DateTime<Utc>,
pub updated_at: chrono::DateTime<Utc>,
}
impl From<model_provider::Model> for ProviderResponse {
fn from(p: model_provider::Model) -> Self {
Self {
id: p.id,
name: p.name,
display_name: p.display_name,
website: p.website,
status: p.status,
created_at: p.created_at,
updated_at: p.updated_at,
}
}
}
/// List all providers ordered by display name.
pub async fn list_providers(db: &AppDatabase) -> Result<Vec<ProviderResponse>, AgentError> {
let providers = ProviderEntity::find()
.order_by_asc(model_provider::Column::DisplayName)
.all(db)
.await?;
Ok(providers.into_iter().map(ProviderResponse::from).collect())
}
/// Get a single provider by ID.
pub async fn get_provider(db: &AppDatabase, id: Uuid) -> Result<ProviderResponse, AgentError> {
let provider = ProviderEntity::find_by_id(id)
.one(db)
.await?
.ok_or_else(|| AgentError::NotFound(format!("Provider not found: {}", id)))?;
Ok(ProviderResponse::from(provider))
}
/// Create a new provider.
pub async fn create_provider(
db: &AppDatabase,
request: CreateProviderRequest,
) -> Result<ProviderResponse, AgentError> {
let now = Utc::now();
let active = model_provider::ActiveModel {
id: Set(Uuid::now_v7()),
name: Set(request.name),
display_name: Set(request.display_name),
website: Set(request.website),
status: Set(ModelStatus::Active.to_string()),
created_at: Set(now),
updated_at: Set(now),
..Default::default()
};
let model = active.insert(db).await?;
Ok(ProviderResponse::from(model))
}
/// Update an existing provider.
pub async fn update_provider(
db: &AppDatabase,
id: Uuid,
request: UpdateProviderRequest,
) -> Result<ProviderResponse, AgentError> {
let provider = ProviderEntity::find_by_id(id)
.one(db)
.await?
.ok_or_else(|| AgentError::NotFound(format!("Provider not found: {}", id)))?;
let mut active: model_provider::ActiveModel = provider.into();
if let Some(display_name) = request.display_name {
active.display_name = Set(display_name);
}
if let Some(website) = request.website {
active.website = Set(Some(website));
}
if let Some(status) = request.status {
active.status = Set(status);
}
active.updated_at = Set(Utc::now());
let model = active.update(db).await?;
Ok(ProviderResponse::from(model))
}
/// Delete a provider by ID.
pub async fn delete_provider(db: &AppDatabase, id: Uuid) -> Result<(), AgentError> {
ProviderEntity::delete_by_id(id).exec(db).await?;
Ok(())
}