forked from boos/BoosAPI
feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
pub use sea_orm_migration::prelude::*;
|
||||
|
||||
mod m20240101_000001_init;
|
||||
mod m20240102_000001_add_token_fields;
|
||||
mod m20240103_000001_add_mcp_timeout_headers;
|
||||
mod m20240104_000001_add_mcp_icon;
|
||||
mod m20250105_000001_context_compression;
|
||||
mod m20250106_000001_add_message_status;
|
||||
mod m20250107_000001_add_provider_custom_headers;
|
||||
mod m20250108_000001_add_provider_icon;
|
||||
mod m20250109_000001_add_conversation_categories;
|
||||
mod m20250110_000001_add_memory_item_index_status;
|
||||
mod m20250111_000001_add_memory_item_index_error;
|
||||
mod m20250113_000001_add_memory_namespace_settings;
|
||||
mod m20250114_000001_add_memory_namespace_icon_sort;
|
||||
mod m20250115_000001_add_knowledge_base_icon_sort;
|
||||
mod m20250116_000001_add_knowledge_base_retrieval_settings;
|
||||
mod m20250117_000001_add_knowledge_base_chunking_config;
|
||||
mod m20250118_000001_add_knowledge_document_type;
|
||||
mod m20250119_000001_add_knowledge_document_index_error;
|
||||
mod m20250120_000001_add_message_timing;
|
||||
mod m20250121_000001_add_conversation_parent_id;
|
||||
mod m20250122_000001_merge_thinking_to_content;
|
||||
mod m20250123_000001_add_category_system_prompt;
|
||||
mod m20250717_000001_add_agent_support;
|
||||
mod m20250718_000001_add_sdk_context_backup;
|
||||
mod m20250719_000001_add_skill_states;
|
||||
mod m20250720_000001_add_provider_builtin_id;
|
||||
mod m20260417_000001_add_category_default_templates;
|
||||
mod m20260428_000001_add_drawing_history;
|
||||
mod m20260430_000001_add_conversation_thinking_level;
|
||||
mod m20260501_000001_add_knowledge_base_rerank_settings;
|
||||
mod m20260504_000001_split_openai_compatible_provider_types;
|
||||
mod m20260515_000001_add_knowledge_base_index_schedule;
|
||||
mod m20260518_000001_add_builtin_model_deletions;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigratorTrait for Migrator {
|
||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||
vec![
|
||||
Box::new(m20240101_000001_init::Migration),
|
||||
Box::new(m20240102_000001_add_token_fields::Migration),
|
||||
Box::new(m20240103_000001_add_mcp_timeout_headers::Migration),
|
||||
Box::new(m20240104_000001_add_mcp_icon::Migration),
|
||||
Box::new(m20250105_000001_context_compression::Migration),
|
||||
Box::new(m20250106_000001_add_message_status::Migration),
|
||||
Box::new(m20250107_000001_add_provider_custom_headers::Migration),
|
||||
Box::new(m20250108_000001_add_provider_icon::Migration),
|
||||
Box::new(m20250109_000001_add_conversation_categories::Migration),
|
||||
Box::new(m20250110_000001_add_memory_item_index_status::Migration),
|
||||
Box::new(m20250111_000001_add_memory_item_index_error::Migration),
|
||||
Box::new(m20250113_000001_add_memory_namespace_settings::Migration),
|
||||
Box::new(m20250114_000001_add_memory_namespace_icon_sort::Migration),
|
||||
Box::new(m20250115_000001_add_knowledge_base_icon_sort::Migration),
|
||||
Box::new(m20250116_000001_add_knowledge_base_retrieval_settings::Migration),
|
||||
Box::new(m20250117_000001_add_knowledge_base_chunking_config::Migration),
|
||||
Box::new(m20250118_000001_add_knowledge_document_type::Migration),
|
||||
Box::new(m20250119_000001_add_knowledge_document_index_error::Migration),
|
||||
Box::new(m20250120_000001_add_message_timing::Migration),
|
||||
Box::new(m20250121_000001_add_conversation_parent_id::Migration),
|
||||
Box::new(m20250122_000001_merge_thinking_to_content::Migration),
|
||||
Box::new(m20250123_000001_add_category_system_prompt::Migration),
|
||||
Box::new(m20250717_000001_add_agent_support::Migration),
|
||||
Box::new(m20250718_000001_add_sdk_context_backup::Migration),
|
||||
Box::new(m20250719_000001_add_skill_states::Migration),
|
||||
Box::new(m20250720_000001_add_provider_builtin_id::Migration),
|
||||
Box::new(m20260417_000001_add_category_default_templates::Migration),
|
||||
Box::new(m20260428_000001_add_drawing_history::Migration),
|
||||
Box::new(m20260430_000001_add_conversation_thinking_level::Migration),
|
||||
Box::new(m20260501_000001_add_knowledge_base_rerank_settings::Migration),
|
||||
Box::new(m20260504_000001_split_openai_compatible_provider_types::Migration),
|
||||
Box::new(m20260515_000001_add_knowledge_base_index_schedule::Migration),
|
||||
Box::new(m20260518_000001_add_builtin_model_deletions::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sea_orm_migration::sea_orm::{
|
||||
ConnectOptions, ConnectionTrait, Database, DatabaseConnection, DbBackend, Statement,
|
||||
};
|
||||
|
||||
async fn sqlite_test_db() -> DatabaseConnection {
|
||||
let mut opts = ConnectOptions::new("sqlite::memory:");
|
||||
opts.max_connections(1)
|
||||
.min_connections(1)
|
||||
.sqlx_logging(false);
|
||||
Database::connect(opts)
|
||||
.await
|
||||
.expect("connect sqlite test db")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_category_default_template_columns_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
for column in [
|
||||
"default_provider_id",
|
||||
"default_model_id",
|
||||
"default_temperature",
|
||||
"default_max_tokens",
|
||||
"default_top_p",
|
||||
"default_frequency_penalty",
|
||||
] {
|
||||
assert!(
|
||||
manager
|
||||
.has_column("conversation_categories", column)
|
||||
.await
|
||||
.expect("check migrated column"),
|
||||
"missing column {column}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_drawing_history_tables_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
for table in ["drawing_generations", "drawing_images"] {
|
||||
assert!(
|
||||
manager.has_table(table).await.expect("check drawing table"),
|
||||
"missing table {table}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_builtin_model_deletions_table_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
assert!(
|
||||
manager
|
||||
.has_table("builtin_model_deletions")
|
||||
.await
|
||||
.expect("check builtin model deletions table"),
|
||||
"missing builtin_model_deletions table"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_conversation_thinking_level_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
assert!(
|
||||
manager
|
||||
.has_column("conversations", "thinking_level")
|
||||
.await
|
||||
.expect("check thinking level column"),
|
||||
"missing conversations.thinking_level"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_knowledge_base_rerank_settings_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
for column in ["rerank_provider", "rerank_candidate_k"] {
|
||||
assert!(
|
||||
manager
|
||||
.has_column("knowledge_bases", column)
|
||||
.await
|
||||
.expect("check knowledge base rerank column"),
|
||||
"missing knowledge_bases.{column}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_up_adds_knowledge_base_index_schedule_on_sqlite() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
|
||||
let manager = SchemaManager::new(&db);
|
||||
for column in ["index_concurrency", "index_interval_ms"] {
|
||||
assert!(
|
||||
manager
|
||||
.has_column("knowledge_bases", column)
|
||||
.await
|
||||
.expect("check knowledge base index schedule column"),
|
||||
"missing knowledge_bases.{column}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn split_openai_compatible_provider_types_migration_updates_builtin_rows() {
|
||||
let db = sqlite_test_db().await;
|
||||
let manager = SchemaManager::new(&db);
|
||||
|
||||
m20240101_000001_init::Migration
|
||||
.up(&manager)
|
||||
.await
|
||||
.expect("run init migration");
|
||||
m20250720_000001_add_provider_builtin_id::Migration
|
||||
.up(&manager)
|
||||
.await
|
||||
.expect("add builtin_id column");
|
||||
|
||||
db.execute_unprepared(
|
||||
r#"INSERT INTO providers
|
||||
(id, name, provider_type, api_host, enabled, sort_order, created_at, updated_at, builtin_id)
|
||||
VALUES
|
||||
('provider-deepseek', 'DeepSeek', 'openai', 'https://api.deepseek.com', 1, 0, 1, 1, 'deepseek'),
|
||||
('provider-xai', 'xAI', 'openai', 'https://api.x.ai', 1, 0, 1, 1, 'xai'),
|
||||
('provider-glm', 'GLM', 'openai', 'https://open.bigmodel.cn/api/paas', 1, 0, 1, 1, 'glm'),
|
||||
('provider-siliconflow', 'SiliconFlow', 'openai', 'https://api.siliconflow.cn', 1, 0, 1, 1, 'siliconflow'),
|
||||
('provider-custom', 'Custom', 'openai', 'https://api.example.com', 1, 0, 1, 1, NULL)"#,
|
||||
)
|
||||
.await
|
||||
.expect("insert provider rows");
|
||||
|
||||
m20260504_000001_split_openai_compatible_provider_types::Migration
|
||||
.up(&manager)
|
||||
.await
|
||||
.expect("split provider types");
|
||||
|
||||
let rows = db
|
||||
.query_all(Statement::from_string(
|
||||
DbBackend::Sqlite,
|
||||
"SELECT id, provider_type FROM providers ORDER BY id".to_string(),
|
||||
))
|
||||
.await
|
||||
.expect("query providers");
|
||||
let values: Vec<(String, String)> = rows
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
(
|
||||
row.try_get("", "id").unwrap(),
|
||||
row.try_get("", "provider_type").unwrap(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(
|
||||
values,
|
||||
vec![
|
||||
("provider-custom".to_string(), "openai".to_string()),
|
||||
("provider-deepseek".to_string(), "deepseek".to_string()),
|
||||
("provider-glm".to_string(), "glm".to_string()),
|
||||
(
|
||||
"provider-siliconflow".to_string(),
|
||||
"siliconflow".to_string()
|
||||
),
|
||||
("provider-xai".to_string(), "xai".to_string()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn migrator_refresh_round_trips_latest_sqlite_schema() {
|
||||
let db = sqlite_test_db().await;
|
||||
|
||||
Migrator::up(&db, None)
|
||||
.await
|
||||
.expect("run sqlite migrations");
|
||||
Migrator::refresh(&db)
|
||||
.await
|
||||
.expect("refresh sqlite migrations");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user