Phase 41: Profile System Expansion

- ProfileType enum: Execution, Retrieval, Memory, Observer
- Per-type endpoints: /profiles/retrieval, /profiles/memory, /profiles/observer
- profile_type field on ModelProfile
- All tests pass
This commit is contained in:
root 2026-04-23 03:07:22 -05:00
parent e442d401d2
commit f59ddbebd4
2 changed files with 40 additions and 0 deletions

View File

@ -31,6 +31,10 @@ pub fn router(registry: Registry) -> Router {
// Phase 17: model profiles // Phase 17: model profiles
.route("/profiles", post(create_profile).get(list_profiles)) .route("/profiles", post(create_profile).get(list_profiles))
.route("/profiles/{id}", get(get_profile).delete(delete_profile)) .route("/profiles/{id}", get(get_profile).delete(delete_profile))
// Phase 41: profile-type routes
.route("/profiles/retrieval", get(list_retrieval_profiles))
.route("/profiles/memory", get(list_memory_profiles))
.route("/profiles/observer", get(list_observer_profiles))
.with_state(registry) .with_state(registry)
} }
@ -398,6 +402,9 @@ struct CreateProfileRequest {
/// indexes to. Defaults to Parquet+HNSW. /// indexes to. Defaults to Parquet+HNSW.
#[serde(default)] #[serde(default)]
vector_backend: shared::types::VectorBackend, vector_backend: shared::types::VectorBackend,
/// Phase 41: Profile type for routing + activation behavior.
#[serde(default)]
profile_type: shared::types::ProfileType,
} }
fn default_embed_model_req() -> String { "nomic-embed-text".to_string() } fn default_embed_model_req() -> String { "nomic-embed-text".to_string() }
@ -417,6 +424,7 @@ async fn create_profile(
created_by: req.created_by, created_by: req.created_by,
bucket: req.bucket, bucket: req.bucket,
vector_backend: req.vector_backend, vector_backend: req.vector_backend,
profile_type: req.profile_type,
}; };
match registry.put_profile(profile).await { match registry.put_profile(profile).await {
Ok(p) => Ok((StatusCode::CREATED, Json(p))), Ok(p) => Ok((StatusCode::CREATED, Json(p))),
@ -428,6 +436,24 @@ async fn list_profiles(State(registry): State<Registry>) -> impl IntoResponse {
Json(registry.list_profiles().await) Json(registry.list_profiles().await)
} }
async fn list_retrieval_profiles(State(registry): State<Registry>) -> impl IntoResponse {
let all = registry.list_profiles().await;
let retrieval: Vec<_> = all.into_iter().filter(|p| p.profile_type == shared::types::ProfileType::Retrieval).collect();
Json(retrieval)
}
async fn list_memory_profiles(State(registry): State<Registry>) -> impl IntoResponse {
let all = registry.list_profiles().await;
let memory: Vec<_> = all.into_iter().filter(|p| p.profile_type == shared::types::ProfileType::Memory).collect();
Json(memory)
}
async fn list_observer_profiles(State(registry): State<Registry>) -> impl IntoResponse {
let all = registry.list_profiles().await;
let observer: Vec<_> = all.into_iter().filter(|p| p.profile_type == shared::types::ProfileType::Observer).collect();
Json(observer)
}
async fn get_profile( async fn get_profile(
State(registry): State<Registry>, State(registry): State<Registry>,
Path(id): Path<String>, Path(id): Path<String>,

View File

@ -269,6 +269,20 @@ pub struct ModelProfile {
/// / 5M+ vector workloads. /// / 5M+ vector workloads.
#[serde(default)] #[serde(default)]
pub vector_backend: VectorBackend, pub vector_backend: VectorBackend,
/// Phase 41: Profile type for routing + activation behavior.
/// Default Execution for backward compatibility.
#[serde(default)]
pub profile_type: ProfileType,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ProfileType {
#[default]
Execution,
Retrieval,
Memory,
Observer,
} }
fn default_embed_model() -> String { "nomic-embed-text".to_string() } fn default_embed_model() -> String { "nomic-embed-text".to_string() }