Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
914f4e9
feat: model settings
hanakannzashi Dec 10, 2025
0a6b607
feat: model settings
hanakannzashi Dec 10, 2025
f0beb05
feat: model settings
hanakannzashi Dec 10, 2025
431fe37
chore: fmt
hanakannzashi Dec 10, 2025
70f0938
fix: model list
hanakannzashi Dec 11, 2025
9f50407
fix: model list
hanakannzashi Dec 11, 2025
e4ff88e
fix: rename to public
hanakannzashi Dec 11, 2025
2399f3f
chore: extra line
hanakannzashi Dec 11, 2025
b0e2a43
refactor: batch get model settings
hanakannzashi Dec 11, 2025
b1ea950
refactor: batch get model settings
hanakannzashi Dec 11, 2025
b07a0a7
refactor: rename
hanakannzashi Dec 11, 2025
963d24d
refactor: rename
hanakannzashi Dec 11, 2025
306e4e0
refactor: rename
hanakannzashi Dec 11, 2025
27a2481
test
hanakannzashi Dec 11, 2025
608d2af
refactor
hanakannzashi Dec 11, 2025
2e86464
refactor
hanakannzashi Dec 11, 2025
53e8698
refactor
hanakannzashi Dec 11, 2025
040ad33
refactor
hanakannzashi Dec 11, 2025
cb6f116
refactor
hanakannzashi Dec 11, 2025
ce6eefa
refactor
hanakannzashi Dec 11, 2025
b324375
refactor
hanakannzashi Dec 11, 2025
5a57c95
refactor
hanakannzashi Dec 11, 2025
fca0b77
refactor
hanakannzashi Dec 11, 2025
fff23e3
refactor
hanakannzashi Dec 11, 2025
b617df6
Merge branch 'main' into feat/model-settings
hanakannzashi Dec 11, 2025
465233b
feat: delete model
hanakannzashi Dec 11, 2025
6843c3c
Merge branch 'main' into feat/model-settings
hanakannzashi Dec 16, 2025
a264f8e
refactor: model system prompt
hanakannzashi Dec 16, 2025
73b6e51
refactor: model system prompt
hanakannzashi Dec 16, 2025
9265688
fix
hanakannzashi Dec 17, 2025
951c305
feat: global config
hanakannzashi Dec 17, 2025
3df5aec
fix: get model
hanakannzashi Dec 17, 2025
fa994cc
test: globals test
hanakannzashi Dec 17, 2025
872668a
Merge branch 'main' into feat/model-settings
hanakannzashi Dec 19, 2025
4d73335
fix: merge
hanakannzashi Dec 19, 2025
72a9f0c
fix: migration
hanakannzashi Dec 19, 2025
ae477e3
fix: path
hanakannzashi Dec 23, 2025
8c23fc3
fix: path
hanakannzashi Dec 23, 2025
ebcaf4b
refactor: rename
hanakannzashi Dec 23, 2025
123ae22
refactor: rename
hanakannzashi Dec 23, 2025
e794602
refactor: rename
hanakannzashi Dec 23, 2025
56db0fa
fix: remove refresh logic
hanakannzashi Dec 23, 2025
52bace3
refactor
hanakannzashi Dec 23, 2025
4101f41
feat: system prompt cache
hanakannzashi Dec 23, 2025
a968617
Merge branch 'main' into feat/model-settings
hanakannzashi Dec 23, 2025
5b64326
fix: remove unused
hanakannzashi Dec 23, 2025
afae683
fix: tests
hanakannzashi Dec 23, 2025
8fc0f48
fix: tests
hanakannzashi Dec 23, 2025
48ccce1
fix: sql
hanakannzashi Dec 23, 2025
fa0b1fc
fix: path
hanakannzashi Dec 23, 2025
d9acfd0
chore: docs
hanakannzashi Dec 23, 2025
2e81242
refactor: rename global configs to system settings
think-in-universe Dec 24, 2025
a595a61
refactor: rename system settings test
think-in-universe Dec 24, 2025
bdc2a7e
refactor: rename model settings cache
think-in-universe Dec 24, 2025
d6ebe51
refactor: rename system settings to system configs
think-in-universe Dec 24, 2025
63d6695
feat: make model public by default
think-in-universe Dec 24, 2025
ba4d482
refactor: default model visiblity constant
think-in-universe Dec 24, 2025
c3a7f6c
feat: make configs accessible by all users
think-in-universe Dec 24, 2025
2967bbe
refactor: rename functions
think-in-universe Dec 24, 2025
84412e6
style: code format
think-in-universe Dec 24, 2025
5cbfee4
fix: validate system prompt
think-in-universe Dec 24, 2025
0a60c53
fix: update logging
think-in-universe Dec 24, 2025
e6af3ee
fix: model not available
think-in-universe Dec 24, 2025
7511eb0
fix: model cache
think-in-universe Dec 24, 2025
fc1e3f3
fix: validate model id
think-in-universe Dec 24, 2025
b7f7f1d
refactor: update args
think-in-universe Dec 24, 2025
427accb
fix: invalidate cache after database ops
think-in-universe Dec 24, 2025
f8f5630
fix: error handling
think-in-universe Dec 24, 2025
b5f2cf8
fix: update data
think-in-universe Dec 24, 2025
e41213c
Revert "fix: update data"
think-in-universe Dec 24, 2025
37c19b1
feat: upsert models
think-in-universe Dec 24, 2025
53fd188
refactor: upsert system configs
think-in-universe Dec 24, 2025
7378abe
test: fix flaky test
think-in-universe Dec 24, 2025
81fc80a
fix: resolve comments
think-in-universe Dec 24, 2025
93952f1
test: fix flaky test
think-in-universe Dec 24, 2025
074ede9
fix: update model
think-in-universe Dec 24, 2025
c0057fe
fix: race condition for model cache
think-in-universe Dec 24, 2025
66ff91a
fix: system configs JSON parsig
think-in-universe Dec 24, 2025
f231663
fix: update model settings cache ttl
think-in-universe Dec 24, 2025
49b09ff
fix: make system configs test serial
think-in-universe Dec 24, 2025
d19b8d6
test: fix test failure
think-in-universe Dec 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions crates/api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use services::{
conversation::service::ConversationServiceImpl,
file::service::FileServiceImpl,
metrics::{MockMetricsService, OtlpMetricsService},
model::service::ModelServiceImpl,
response::service::OpenAIProxy,
user::UserServiceImpl,
user::UserSettingsServiceImpl,
Expand Down Expand Up @@ -71,6 +72,8 @@ async fn main() -> anyhow::Result<()> {
let app_config_repo = db.app_config_repository();
let near_nonce_repo = db.near_nonce_repository();
let analytics_repo = db.analytics_repository();
let system_configs_repo = db.system_configs_repository();
let model_repo = db.model_repository();

// Create services
tracing::info!("Initializing services...");
Expand All @@ -89,9 +92,9 @@ async fn main() -> anyhow::Result<()> {

let user_service = Arc::new(UserServiceImpl::new(user_repo.clone()));

let user_settings_service = Arc::new(UserSettingsServiceImpl::new(
user_settings_repo as Arc<dyn services::user::ports::UserSettingsRepository>,
));
let user_settings_service = Arc::new(UserSettingsServiceImpl::new(user_settings_repo));

let model_service = Arc::new(ModelServiceImpl::new(model_repo));

// Initialize VPC credentials service and get API key
let vpc_auth_config = if config.vpc_auth.is_configured() {
Expand Down Expand Up @@ -150,6 +153,15 @@ async fn main() -> anyhow::Result<()> {
analytics_repo as Arc<dyn services::analytics::AnalyticsRepository>,
));

// Initialize system configs service
tracing::info!("Initializing system configs service...");
let system_configs_service = Arc::new(
services::system_configs::service::SystemConfigsServiceImpl::new(
system_configs_repo
as Arc<dyn services::system_configs::ports::SystemConfigsRepository>,
),
);

// Initialize metrics service
tracing::info!("Initializing metrics service...");
let metrics_service: Arc<dyn services::metrics::MetricsServiceTrait> =
Expand Down Expand Up @@ -209,6 +221,8 @@ async fn main() -> anyhow::Result<()> {
oauth_service,
user_service,
user_settings_service,
model_service,
system_configs_service,
session_repository: session_repo,
proxy_service,
conversation_service,
Expand All @@ -222,6 +236,7 @@ async fn main() -> anyhow::Result<()> {
analytics_service,
near_rpc_url: config.near.rpc_url.clone(),
near_balance_cache: Arc::new(tokio::sync::RwLock::new(std::collections::HashMap::new())),
model_settings_cache: Arc::new(tokio::sync::RwLock::new(std::collections::HashMap::new())),
};

// Create router with CORS support
Expand Down
176 changes: 166 additions & 10 deletions crates/api/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,6 @@ impl From<services::user::ports::UserSettingsContent> for UserSettingsContent {
}
}

/// User settings response
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UserSettingsResponse {
/// User ID
pub user_id: UserId,
/// Settings content (serialized as "settings")
#[serde(rename = "settings")]
pub content: UserSettingsContent,
}

/// User settings update request
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UpdateUserSettingsRequest {
Expand Down Expand Up @@ -251,6 +241,124 @@ impl UpdateUserSettingsPartiallyRequest {
}
}

/// User settings response
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UserSettingsResponse {
/// User ID
pub user_id: UserId,
/// Settings content (serialized as "settings")
#[serde(rename = "settings")]
pub content: UserSettingsContent,
}

/// Model settings content for API responses
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ModelSettings {
/// Whether models are public (visible/usable in responses)
pub public: bool,
/// Optional system-level system prompt for this model
#[serde(skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
}

impl From<services::model::ports::ModelSettings> for ModelSettings {
fn from(content: services::model::ports::ModelSettings) -> Self {
Self {
public: content.public,
system_prompt: content.system_prompt,
}
}
}

impl From<ModelSettings> for services::model::ports::ModelSettings {
fn from(content: ModelSettings) -> Self {
Self {
public: content.public,
system_prompt: content.system_prompt,
}
}
}

/// Partial model settings for API requests
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct PartialModelSettings {
/// Whether models are public (visible/usable in responses)
pub public: Option<bool>,
/// Optional system-level system prompt for this model
pub system_prompt: Option<String>,
}

impl From<services::model::ports::PartialModelSettings> for PartialModelSettings {
fn from(content: services::model::ports::PartialModelSettings) -> Self {
Self {
public: content.public,
system_prompt: content.system_prompt,
}
}
}

impl From<PartialModelSettings> for services::model::ports::PartialModelSettings {
fn from(content: PartialModelSettings) -> Self {
Self {
public: content.public,
system_prompt: content.system_prompt,
}
}
}

/// Complete model response
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ModelResponse {
/// External model identifier (e.g. "gpt-4.1")
pub model_id: String,
/// Settings stored for this model
pub settings: ModelSettings,
}

impl From<services::model::ports::Model> for ModelResponse {
fn from(model: services::model::ports::Model) -> Self {
Self {
model_id: model.model_id,
settings: model.settings.into(),
}
}
}

/// Model upsert request
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UpsertModelsRequest {
pub settings: ModelSettings,
}

/// Model settings update request (partial update)
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UpdateModelRequest {
pub settings: Option<PartialModelSettings>,
}

/// Batch model upsert request
///
/// Maps model_id to partial settings to update.
/// Example: { "gpt-4": { "public": true }, "gpt-3.5": { "public": false, "system_prompt": "..." } }
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct BatchUpsertModelsRequest {
#[serde(flatten)]
pub models: std::collections::HashMap<String, PartialModelSettings>,
}

/// Model list response with pagination
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct ModelListResponse {
/// List of models
pub models: Vec<ModelResponse>,
/// Maximum number of items returned
pub limit: i64,
/// Number of items skipped
pub offset: i64,
/// Total number of models
pub total: i64,
}

/// Paginated user list response
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UserListResponse {
Expand All @@ -264,6 +372,54 @@ pub struct UserListResponse {
pub total: u64,
}

/// System configs response
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct SystemConfigsResponse {
/// Default model identifier to use when not specified
#[serde(skip_serializing_if = "Option::is_none")]
pub default_model: Option<String>,
}

impl From<services::system_configs::ports::SystemConfigs> for SystemConfigsResponse {
fn from(config: services::system_configs::ports::SystemConfigs) -> Self {
Self {
default_model: config.default_model,
}
}
}

/// System configs upsert request (full replace)
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UpsertSystemConfigsRequest {
/// Default model identifier to use when not specified
#[serde(skip_serializing_if = "Option::is_none")]
pub default_model: Option<String>,
}

impl From<UpsertSystemConfigsRequest> for services::system_configs::ports::SystemConfigs {
fn from(req: UpsertSystemConfigsRequest) -> Self {
services::system_configs::ports::SystemConfigs {
default_model: req.default_model,
}
}
}

/// System configs update request (partial)
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct UpdateSystemConfigsRequest {
/// Default model identifier to use when not specified
#[serde(skip_serializing_if = "Option::is_none")]
pub default_model: Option<String>,
}

impl From<UpdateSystemConfigsRequest> for services::system_configs::ports::PartialSystemConfigs {
fn from(req: UpdateSystemConfigsRequest) -> Self {
services::system_configs::ports::PartialSystemConfigs {
default_model: req.default_model,
}
}
}

/// File list response with pagination
#[derive(Debug, Serialize, Deserialize, ToSchema)]
pub struct FileListResponse {
Expand Down
15 changes: 15 additions & 0 deletions crates/api/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ use utoipa::OpenApi;
crate::routes::users::get_current_user,
// Admin endpoints
crate::routes::admin::list_users,
crate::routes::admin::list_models,
crate::routes::admin::batch_upsert_models,
crate::routes::admin::delete_model,
crate::routes::admin::upsert_system_configs,
// Configs endpoints
crate::routes::configs::get_system_configs,
crate::routes::users::get_user_settings,
crate::routes::users::update_user_settings_partially,
crate::routes::users::update_user_settings,
Expand All @@ -47,6 +53,14 @@ use utoipa::OpenApi;
crate::models::UserSettingsResponse,
crate::models::UpdateUserSettingsPartiallyRequest,
crate::models::UpdateUserSettingsRequest,
// Model settings / model admin models
crate::models::ModelResponse,
crate::models::ModelListResponse,
crate::models::BatchUpsertModelsRequest,
crate::models::UpdateModelRequest,
// System configs models
crate::models::SystemConfigsResponse,
crate::models::UpdateSystemConfigsRequest,
// Attestation models
crate::models::ApiGatewayAttestation,
crate::models::ModelAttestation,
Expand All @@ -58,6 +72,7 @@ use utoipa::OpenApi;
(name = "Auth", description = "OAuth authentication endpoints"),
(name = "Users", description = "User profile management endpoints"),
(name = "Admin", description = "Admin management endpoints"),
(name = "Configs", description = "System configuration endpoints"),
(name = "attestation", description = "Attestation reporting endpoints for TEE verification")
)
)]
Expand Down
Loading