Skip to main content

systemprompt_runtime/optimization/
inventory.rs

1//! Core inventory orchestration uses configured services roots and
2//! organizational ownership.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use super::OptimizationError;
8use crate::AppContext;
9use systemprompt_identifiers::UserId;
10use systemprompt_marketplace::inventory::{
11    BaselineCapture, BaselinePreparation, BaselineScope, InventoryService, InventoryStatus,
12};
13pub use systemprompt_marketplace::inventory::{LatestPublication, LatestPublicationStatus};
14
15pub async fn refresh(
16    ctx: &AppContext,
17    owner: &UserId,
18) -> Result<InventoryStatus, OptimizationError> {
19    let services = load_services(ctx, owner).await?;
20    Ok(
21        InventoryService::new(ctx.managed_repository().as_ref().clone())
22            .refresh(owner, ctx.app_paths().system().services(), &services)
23            .await?,
24    )
25}
26
27pub async fn prepare_baselines(
28    ctx: &AppContext,
29    owner: &UserId,
30    actor: &UserId,
31    request: &BaselinePreparation,
32) -> Result<Vec<BaselineCapture>, OptimizationError> {
33    let services = load_services(ctx, owner).await?;
34    let service = InventoryService::new(ctx.managed_repository().as_ref().clone());
35    service
36        .refresh(owner, ctx.app_paths().system().services(), &services)
37        .await?;
38    Ok(service
39        .prepare_baselines(
40            &BaselineScope {
41                owner,
42                actor,
43                root: ctx.app_paths().system().services(),
44                services: &services,
45            },
46            request,
47        )
48        .await?)
49}
50
51pub async fn publish_latest(
52    ctx: &AppContext,
53    owner: &UserId,
54    actor: &UserId,
55) -> Result<Vec<LatestPublication>, OptimizationError> {
56    let services = load_services(ctx, owner).await?;
57    let service = InventoryService::new(ctx.managed_repository().as_ref().clone());
58    service
59        .refresh(owner, ctx.app_paths().system().services(), &services)
60        .await?;
61    let mut guard = ctx.publish_guard().lock().await;
62    Ok(service
63        .publish_latest(
64            &BaselineScope {
65                owner,
66                actor,
67                root: ctx.app_paths().system().services(),
68                services: &services,
69            },
70            &mut guard,
71        )
72        .await?)
73}
74
75async fn load_services(
76    ctx: &AppContext,
77    owner: &UserId,
78) -> Result<systemprompt_models::services::ServicesConfig, OptimizationError> {
79    match systemprompt_loader::ConfigLoader::load() {
80        Ok(services) => Ok(services),
81        Err(error) => {
82            tracing::warn!(%error, "Configured inventory could not be loaded; previous inventory retained");
83            ctx.managed_repository()
84                .record_inventory_failure(owner)
85                .await?;
86            Err(OptimizationError::Source(format!(
87                "Configured inventory could not be loaded; previous inventory retained: {error}"
88            )))
89        },
90    }
91}