- 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
115 lines
3.4 KiB
Rust
115 lines
3.4 KiB
Rust
//! Model capability management — CRUD.
|
|
|
|
use chrono::Utc;
|
|
use db::database::AppDatabase;
|
|
use models::agents::CapabilityType;
|
|
use models::agents::model_capability;
|
|
use sea_orm::*;
|
|
|
|
use crate::error::AgentError;
|
|
|
|
#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
|
|
pub struct CreateModelCapabilityRequest {
|
|
pub model_version_id: i64,
|
|
pub capability: String,
|
|
#[serde(default)]
|
|
pub is_supported: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Deserialize, utoipa::ToSchema)]
|
|
pub struct UpdateModelCapabilityRequest {
|
|
pub is_supported: Option<bool>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
|
pub struct ModelCapabilityResponse {
|
|
pub id: i64,
|
|
pub model_version_id: i64,
|
|
pub capability: String,
|
|
pub is_supported: bool,
|
|
pub created_at: chrono::DateTime<Utc>,
|
|
}
|
|
|
|
impl From<model_capability::Model> for ModelCapabilityResponse {
|
|
fn from(mc: model_capability::Model) -> Self {
|
|
Self {
|
|
id: mc.id,
|
|
model_version_id: mc.model_version_id,
|
|
capability: mc.capability,
|
|
is_supported: mc.is_supported,
|
|
created_at: mc.created_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn list_capabilities(
|
|
db: &AppDatabase,
|
|
model_version_id: i64,
|
|
) -> Result<Vec<ModelCapabilityResponse>, AgentError> {
|
|
let caps = model_capability::Entity::find()
|
|
.filter(model_capability::Column::ModelVersionId.eq(model_version_id))
|
|
.order_by_asc(model_capability::Column::Capability)
|
|
.all(db)
|
|
.await?;
|
|
Ok(caps.into_iter().map(ModelCapabilityResponse::from).collect())
|
|
}
|
|
|
|
pub async fn get_capability(
|
|
db: &AppDatabase,
|
|
id: i64,
|
|
) -> Result<ModelCapabilityResponse, AgentError> {
|
|
let cap = model_capability::Entity::find_by_id(id)
|
|
.one(db)
|
|
.await?
|
|
.ok_or_else(|| AgentError::NotFound(format!("Capability record not found: {}", id)))?;
|
|
Ok(ModelCapabilityResponse::from(cap))
|
|
}
|
|
|
|
pub async fn create_capability(
|
|
db: &AppDatabase,
|
|
request: CreateModelCapabilityRequest,
|
|
) -> Result<ModelCapabilityResponse, AgentError> {
|
|
let _ = request
|
|
.capability
|
|
.parse::<CapabilityType>()
|
|
.map_err(|_| AgentError::InvalidInput {
|
|
field: "capability".into(),
|
|
reason: "Invalid capability type".into(),
|
|
})?;
|
|
|
|
let now = Utc::now();
|
|
let active = model_capability::ActiveModel {
|
|
model_version_id: Set(request.model_version_id),
|
|
capability: Set(request.capability),
|
|
is_supported: Set(request.is_supported),
|
|
created_at: Set(now),
|
|
..Default::default()
|
|
};
|
|
let cap = active.insert(db).await?;
|
|
Ok(ModelCapabilityResponse::from(cap))
|
|
}
|
|
|
|
pub async fn update_capability(
|
|
db: &AppDatabase,
|
|
id: i64,
|
|
request: UpdateModelCapabilityRequest,
|
|
) -> Result<ModelCapabilityResponse, AgentError> {
|
|
let cap = model_capability::Entity::find_by_id(id)
|
|
.one(db)
|
|
.await?
|
|
.ok_or_else(|| AgentError::NotFound(format!("Capability record not found: {}", id)))?;
|
|
|
|
let mut active: model_capability::ActiveModel = cap.into();
|
|
if let Some(is_supported) = request.is_supported {
|
|
active.is_supported = Set(is_supported);
|
|
}
|
|
|
|
let cap = active.update(db).await?;
|
|
Ok(ModelCapabilityResponse::from(cap))
|
|
}
|
|
|
|
pub async fn delete_capability(db: &AppDatabase, id: i64) -> Result<(), AgentError> {
|
|
model_capability::Entity::delete_by_id(id).exec(db).await?;
|
|
Ok(())
|
|
}
|