- 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
124 lines
3.7 KiB
Rust
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(())
|
|
}
|