Enable template bot creation and fix bot schema
This commit is contained in:
parent
01264411ba
commit
c242aa010b
8 changed files with 236 additions and 33 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
-- Migration 6.0.5: Add update-summary.bas scheduled automation
|
-- Migration 6.0.5: Add update-summary.bas scheduled automation
|
||||||
-- Description: Creates a scheduled automation that runs every minute to update summaries
|
-- Description: Creates a scheduled automation that runs every minute to update summaries
|
||||||
-- This replaces the announcements system in legacy mode
|
-- This replaces the announcements system in legacy mode
|
||||||
|
-- Note: Bots are now created dynamically during bootstrap based on template folders
|
||||||
|
|
||||||
-- Add name column to system_automations if it doesn't exist
|
-- Add name column to system_automations if it doesn't exist
|
||||||
ALTER TABLE public.system_automations ADD COLUMN IF NOT EXISTS name VARCHAR(255);
|
ALTER TABLE public.system_automations ADD COLUMN IF NOT EXISTS name VARCHAR(255);
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,20 @@ async fn auth_handler(
|
||||||
web::Query(params): web::Query<HashMap<String, String>>,
|
web::Query(params): web::Query<HashMap<String, String>>,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
let _token = params.get("token").cloned().unwrap_or_default();
|
let _token = params.get("token").cloned().unwrap_or_default();
|
||||||
let user_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap();
|
|
||||||
|
// Create or get anonymous user with proper UUID
|
||||||
|
let user_id = {
|
||||||
|
let mut sm = data.session_manager.lock().await;
|
||||||
|
match sm.get_or_create_anonymous_user(None) {
|
||||||
|
Ok(uid) => uid,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to create anonymous user: {}", e);
|
||||||
|
return Ok(HttpResponse::InternalServerError()
|
||||||
|
.json(serde_json::json!({"error": "Failed to create user"})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
|
let bot_id = if let Ok(bot_guid) = std::env::var("BOT_GUID") {
|
||||||
match Uuid::parse_str(&bot_guid) {
|
match Uuid::parse_str(&bot_guid) {
|
||||||
Ok(uuid) => uuid,
|
Ok(uuid) => uuid,
|
||||||
|
|
@ -163,8 +176,35 @@ async fn auth_handler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!("BOT_GUID not set in environment, using nil UUID");
|
// BOT_GUID not set, get first available bot from database
|
||||||
Uuid::nil()
|
use crate::shared::models::schema::bots::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut db_conn = data.conn.lock().unwrap();
|
||||||
|
match bots
|
||||||
|
.filter(is_active.eq(true))
|
||||||
|
.select(id)
|
||||||
|
.first::<Uuid>(&mut *db_conn)
|
||||||
|
.optional()
|
||||||
|
{
|
||||||
|
Ok(Some(first_bot_id)) => {
|
||||||
|
log::info!(
|
||||||
|
"BOT_GUID not set, using first available bot: {}",
|
||||||
|
first_bot_id
|
||||||
|
);
|
||||||
|
first_bot_id
|
||||||
|
}
|
||||||
|
Ok(None) => {
|
||||||
|
error!("No active bots found in database");
|
||||||
|
return Ok(HttpResponse::ServiceUnavailable()
|
||||||
|
.json(serde_json::json!({"error": "No bots available"})));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to query bots: {}", e);
|
||||||
|
return Ok(HttpResponse::InternalServerError()
|
||||||
|
.json(serde_json::json!({"error": "Failed to query bots"})));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let session = {
|
let session = {
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,12 @@ impl BootstrapManager {
|
||||||
use aws_sdk_s3::config::Credentials;
|
use aws_sdk_s3::config::Credentials;
|
||||||
use aws_sdk_s3::config::Region;
|
use aws_sdk_s3::config::Region;
|
||||||
|
|
||||||
info!("Uploading template bots to MinIO...");
|
info!("Uploading template bots to MinIO and creating bot entries...");
|
||||||
|
|
||||||
|
// First, create bot entries in database for each template
|
||||||
|
let database_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| config.database_url());
|
||||||
|
let mut conn = diesel::PgConnection::establish(&database_url)?;
|
||||||
|
self.create_bots_from_templates(&mut conn)?;
|
||||||
|
|
||||||
let creds = Credentials::new(
|
let creds = Credentials::new(
|
||||||
&config.minio.access_key,
|
&config.minio.access_key,
|
||||||
|
|
@ -274,6 +279,71 @@ impl BootstrapManager {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_bots_from_templates(&self, conn: &mut diesel::PgConnection) -> Result<()> {
|
||||||
|
use crate::shared::models::schema::bots;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
info!("Creating bot entries from template folders...");
|
||||||
|
|
||||||
|
let templates_dir = Path::new("templates");
|
||||||
|
if !templates_dir.exists() {
|
||||||
|
trace!("Templates directory not found, skipping bot creation");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through each .gbai folder in templates/
|
||||||
|
for entry in std::fs::read_dir(templates_dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() && path.extension().map(|e| e == "gbai").unwrap_or(false) {
|
||||||
|
let bot_folder = path.file_name().unwrap().to_string_lossy().to_string();
|
||||||
|
// Remove .gbai extension to get bot name
|
||||||
|
let bot_name = bot_folder.trim_end_matches(".gbai");
|
||||||
|
|
||||||
|
// Format the name nicely (capitalize first letter of each word)
|
||||||
|
let formatted_name = bot_name
|
||||||
|
.split('_')
|
||||||
|
.map(|word| {
|
||||||
|
let mut chars = word.chars();
|
||||||
|
match chars.next() {
|
||||||
|
None => String::new(),
|
||||||
|
Some(first) => {
|
||||||
|
first.to_uppercase().collect::<String>() + chars.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ");
|
||||||
|
|
||||||
|
// Check if bot already exists
|
||||||
|
let existing: Option<String> = bots::table
|
||||||
|
.filter(bots::name.eq(&formatted_name))
|
||||||
|
.select(bots::name)
|
||||||
|
.first(conn)
|
||||||
|
.optional()?;
|
||||||
|
|
||||||
|
if existing.is_none() {
|
||||||
|
// Insert new bot
|
||||||
|
diesel::sql_query(
|
||||||
|
"INSERT INTO bots (id, name, description, llm_provider, llm_config, context_provider, context_config, is_active) \
|
||||||
|
VALUES (gen_random_uuid(), $1, $2, 'openai', '{\"model\": \"gpt-4\", \"temperature\": 0.7}', 'database', '{}', true)"
|
||||||
|
)
|
||||||
|
.bind::<diesel::sql_types::Text, _>(&formatted_name)
|
||||||
|
.bind::<diesel::sql_types::Text, _>(format!("Bot for {} template", bot_name))
|
||||||
|
.execute(conn)?;
|
||||||
|
|
||||||
|
info!("Created bot entry: {}", formatted_name);
|
||||||
|
} else {
|
||||||
|
trace!("Bot already exists: {}", formatted_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Bot creation from templates completed");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn upload_directory_recursive<'a>(
|
fn upload_directory_recursive<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
client: &'a aws_sdk_s3::Client,
|
client: &'a aws_sdk_s3::Client,
|
||||||
|
|
@ -324,8 +394,6 @@ impl BootstrapManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_migrations(&self, conn: &mut diesel::PgConnection) -> Result<()> {
|
fn apply_migrations(&self, conn: &mut diesel::PgConnection) -> Result<()> {
|
||||||
use diesel::prelude::*;
|
|
||||||
|
|
||||||
info!("Applying database migrations...");
|
info!("Applying database migrations...");
|
||||||
|
|
||||||
let migrations_dir = std::path::Path::new("migrations");
|
let migrations_dir = std::path::Path::new("migrations");
|
||||||
|
|
@ -357,7 +425,7 @@ impl BootstrapManager {
|
||||||
match std::fs::read_to_string(&path) {
|
match std::fs::read_to_string(&path) {
|
||||||
Ok(sql) => {
|
Ok(sql) => {
|
||||||
trace!("Applying migration: {}", filename);
|
trace!("Applying migration: {}", filename);
|
||||||
match diesel::sql_query(&sql).execute(conn) {
|
match conn.batch_execute(&sql) {
|
||||||
Ok(_) => info!("Applied migration: {}", filename),
|
Ok(_) => info!("Applied migration: {}", filename),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// Ignore errors for already applied migrations
|
// Ignore errors for already applied migrations
|
||||||
|
|
|
||||||
|
|
@ -707,12 +707,25 @@ async fn websocket_handler(
|
||||||
) -> Result<HttpResponse, actix_web::Error> {
|
) -> Result<HttpResponse, actix_web::Error> {
|
||||||
let query = web::Query::<HashMap<String, String>>::from_query(req.query_string()).unwrap();
|
let query = web::Query::<HashMap<String, String>>::from_query(req.query_string()).unwrap();
|
||||||
let session_id = query.get("session_id").cloned().unwrap();
|
let session_id = query.get("session_id").cloned().unwrap();
|
||||||
let user_id = query
|
let user_id_string = query
|
||||||
.get("user_id")
|
.get("user_id")
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| Uuid::new_v4().to_string())
|
.unwrap_or_else(|| Uuid::new_v4().to_string())
|
||||||
.replace("undefined", &Uuid::new_v4().to_string());
|
.replace("undefined", &Uuid::new_v4().to_string());
|
||||||
|
|
||||||
|
// Ensure user exists in database before proceeding
|
||||||
|
let user_id = {
|
||||||
|
let user_uuid = Uuid::parse_str(&user_id_string).unwrap_or_else(|_| Uuid::new_v4());
|
||||||
|
let mut sm = data.session_manager.lock().await;
|
||||||
|
match sm.get_or_create_anonymous_user(Some(user_uuid)) {
|
||||||
|
Ok(uid) => uid.to_string(),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to ensure user exists for WebSocket: {}", e);
|
||||||
|
user_id_string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (res, mut session, mut msg_stream) = actix_ws::handle(&req, stream)?;
|
let (res, mut session, mut msg_stream) = actix_ws::handle(&req, stream)?;
|
||||||
let (tx, mut rx) = mpsc::channel::<BotResponse>(100);
|
let (tx, mut rx) = mpsc::channel::<BotResponse>(100);
|
||||||
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
let orchestrator = BotOrchestrator::new(Arc::clone(&data));
|
||||||
|
|
@ -729,7 +742,31 @@ async fn websocket_handler(
|
||||||
.add_connection(session_id.clone(), tx.clone())
|
.add_connection(session_id.clone(), tx.clone())
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let bot_id = std::env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string());
|
// Get first available bot from database
|
||||||
|
let bot_id = {
|
||||||
|
use crate::shared::models::schema::bots::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut db_conn = data.conn.lock().unwrap();
|
||||||
|
match bots
|
||||||
|
.filter(is_active.eq(true))
|
||||||
|
.select(id)
|
||||||
|
.first::<Uuid>(&mut *db_conn)
|
||||||
|
.optional()
|
||||||
|
{
|
||||||
|
Ok(Some(first_bot_id)) => first_bot_id.to_string(),
|
||||||
|
Ok(None) => {
|
||||||
|
error!("No active bots found in database for WebSocket");
|
||||||
|
return Err(actix_web::error::ErrorServiceUnavailable(
|
||||||
|
"No bots available",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to query bots for WebSocket: {}", e);
|
||||||
|
return Err(actix_web::error::ErrorInternalServerError("Database error"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
orchestrator
|
orchestrator
|
||||||
.send_event(
|
.send_event(
|
||||||
|
|
@ -802,8 +839,29 @@ async fn websocket_handler(
|
||||||
match msg {
|
match msg {
|
||||||
WsMessage::Text(text) => {
|
WsMessage::Text(text) => {
|
||||||
message_count += 1;
|
message_count += 1;
|
||||||
let bot_id =
|
// Get first available bot from database
|
||||||
std::env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string());
|
let bot_id = {
|
||||||
|
use crate::shared::models::schema::bots::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut db_conn = data.conn.lock().unwrap();
|
||||||
|
match bots
|
||||||
|
.filter(is_active.eq(true))
|
||||||
|
.select(id)
|
||||||
|
.first::<Uuid>(&mut *db_conn)
|
||||||
|
.optional()
|
||||||
|
{
|
||||||
|
Ok(Some(first_bot_id)) => first_bot_id.to_string(),
|
||||||
|
Ok(None) => {
|
||||||
|
error!("No active bots found");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to query bots: {}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Parse the text as JSON to extract the content field
|
// Parse the text as JSON to extract the content field
|
||||||
let json_value: serde_json::Value = match serde_json::from_str(&text) {
|
let json_value: serde_json::Value = match serde_json::from_str(&text) {
|
||||||
|
|
@ -840,8 +898,29 @@ async fn websocket_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
WsMessage::Close(_) => {
|
WsMessage::Close(_) => {
|
||||||
let bot_id =
|
// Get first available bot from database
|
||||||
std::env::var("BOT_GUID").unwrap_or_else(|_| "default_bot".to_string());
|
let bot_id = {
|
||||||
|
use crate::shared::models::schema::bots::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut db_conn = data.conn.lock().unwrap();
|
||||||
|
match bots
|
||||||
|
.filter(is_active.eq(true))
|
||||||
|
.select(id)
|
||||||
|
.first::<Uuid>(&mut *db_conn)
|
||||||
|
.optional()
|
||||||
|
{
|
||||||
|
Ok(Some(first_bot_id)) => first_bot_id.to_string(),
|
||||||
|
Ok(None) => {
|
||||||
|
error!("No active bots found");
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to query bots: {}", e);
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
orchestrator
|
orchestrator
|
||||||
.send_event(
|
.send_event(
|
||||||
&user_id_clone,
|
&user_id_clone,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ struct LlamaCppResponse {
|
||||||
|
|
||||||
pub async fn ensure_llama_servers_running() -> Result<(), Box<dyn std::error::Error + Send + Sync>>
|
pub async fn ensure_llama_servers_running() -> Result<(), Box<dyn std::error::Error + Send + Sync>>
|
||||||
{
|
{
|
||||||
let llm_local = env::var("LLM_LOCAL").unwrap_or_else(|_| "false".to_string());
|
let llm_local = env::var("LLM_LOCAL").unwrap_or_else(|_| "true".to_string());
|
||||||
|
|
||||||
if llm_local.to_lowercase() != "true" {
|
if llm_local.to_lowercase() != "true" {
|
||||||
info!("ℹ️ LLM_LOCAL is not enabled, skipping local server startup");
|
info!("ℹ️ LLM_LOCAL is not enabled, skipping local server startup");
|
||||||
|
|
@ -215,7 +215,7 @@ async fn start_embedding_server(
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let port = url.split(':').last().unwrap_or("8082");
|
let port = url.split(':').last().unwrap_or("8082");
|
||||||
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
let mut cmd = tokio::process::Command::new("cmd");
|
let mut cmd = tokio::process::Command::new("cmd");
|
||||||
cmd.arg("/c").arg(format!(
|
cmd.arg("/c").arg(format!(
|
||||||
"cd {} && .\\llama-server.exe -m {} --host 0.0.0.0 --port {} --embedding --n-gpu-layers 99",
|
"cd {} && .\\llama-server.exe -m {} --host 0.0.0.0 --port {} --embedding --n-gpu-layers 99",
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -152,15 +152,13 @@ async fn main() -> std::io::Result<()> {
|
||||||
.await
|
.await
|
||||||
.expect("Failed to initialize LLM local server");
|
.expect("Failed to initialize LLM local server");
|
||||||
|
|
||||||
let cache_url = cfg
|
let cache_url = std::env::var("CACHE_URL")
|
||||||
.config_path("cache")
|
.or_else(|_| std::env::var("REDIS_URL"))
|
||||||
.join("redis.conf")
|
.unwrap_or_else(|_| "redis://localhost:6379".to_string());
|
||||||
.display()
|
|
||||||
.to_string();
|
|
||||||
let redis_client = match redis::Client::open(cache_url.as_str()) {
|
let redis_client = match redis::Client::open(cache_url.as_str()) {
|
||||||
Ok(client) => Some(Arc::new(client)),
|
Ok(client) => Some(Arc::new(client)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to connect to Redis: {}", e);
|
log::warn!("Failed to connect to Redis: Redis URL did not parse- {}", e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -272,7 +270,6 @@ async fn main() -> std::io::Result<()> {
|
||||||
app = app
|
app = app
|
||||||
.service(upload_file)
|
.service(upload_file)
|
||||||
.service(index)
|
.service(index)
|
||||||
.service(bot_index)
|
|
||||||
.service(static_files)
|
.service(static_files)
|
||||||
.service(websocket_handler)
|
.service(websocket_handler)
|
||||||
.service(auth_handler)
|
.service(auth_handler)
|
||||||
|
|
@ -284,7 +281,8 @@ async fn main() -> std::io::Result<()> {
|
||||||
.service(start_session)
|
.service(start_session)
|
||||||
.service(get_session_history)
|
.service(get_session_history)
|
||||||
.service(chat_completions_local)
|
.service(chat_completions_local)
|
||||||
.service(embeddings_local);
|
.service(embeddings_local)
|
||||||
|
.service(bot_index); // Must be last - catches all remaining paths
|
||||||
|
|
||||||
#[cfg(feature = "email")]
|
#[cfg(feature = "email")]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,8 @@ impl PackageManager {
|
||||||
if let Ok(mut conn) = PgConnection::establish(&database_url) {
|
if let Ok(mut conn) = PgConnection::establish(&database_url) {
|
||||||
let system_bot_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000")?;
|
let system_bot_id = Uuid::parse_str("00000000-0000-0000-0000-000000000000")?;
|
||||||
diesel::update(bots)
|
diesel::update(bots)
|
||||||
.filter(bot_id.eq(system_bot_id))
|
.filter(id.eq(system_bot_id))
|
||||||
.set(config.eq(serde_json::json!({
|
.set(llm_config.eq(serde_json::json!({
|
||||||
"encrypted_drive_password": encrypted_drive_password,
|
"encrypted_drive_password": encrypted_drive_password,
|
||||||
})))
|
})))
|
||||||
.execute(&mut conn)?;
|
.execute(&mut conn)?;
|
||||||
|
|
@ -165,8 +165,20 @@ impl PackageManager {
|
||||||
"echo \"host all all all md5\" > {{CONF_PATH}}/pg_hba.conf".to_string(),
|
"echo \"host all all all md5\" > {{CONF_PATH}}/pg_hba.conf".to_string(),
|
||||||
"touch {{CONF_PATH}}/pg_ident.conf".to_string(),
|
"touch {{CONF_PATH}}/pg_ident.conf".to_string(),
|
||||||
|
|
||||||
format!("./bin/pg_ctl -D {{{{DATA_PATH}}}}/pgdata -l {{{{LOGS_PATH}}}}/postgres.log start; for i in 1 2 3 4 5 6 7 8 9 10; do ./bin/pg_isready -h localhost -p 5432 >/dev/null 2>&1 && break; echo 'Waiting for PostgreSQL to start...' >&2; sleep 1; done; ./bin/pg_isready -h localhost -p 5432"),
|
// Start PostgreSQL with wait flag
|
||||||
format!("PGPASSWORD={} ./bin/psql -h localhost -U gbuser -d postgres -c \"CREATE DATABASE botserver WITH OWNER gbuser\" 2>&1 | grep -v 'already exists' || true", db_password)
|
"./bin/pg_ctl -D {{DATA_PATH}}/pgdata -l {{LOGS_PATH}}/postgres.log start -w -t 30".to_string(),
|
||||||
|
|
||||||
|
// Wait for PostgreSQL to be fully ready
|
||||||
|
"sleep 5".to_string(),
|
||||||
|
|
||||||
|
// Check if PostgreSQL is accepting connections with retries
|
||||||
|
"for i in $(seq 1 30); do ./bin/pg_isready -h localhost -p 5432 -U gbuser >/dev/null 2>&1 && echo 'PostgreSQL is ready' && break || echo \"Waiting for PostgreSQL... attempt $i/30\" >&2; sleep 2; done".to_string(),
|
||||||
|
|
||||||
|
// Final verification
|
||||||
|
"./bin/pg_isready -h localhost -p 5432 -U gbuser || { echo 'ERROR: PostgreSQL failed to start properly' >&2; cat {{LOGS_PATH}}/postgres.log >&2; exit 1; }".to_string(),
|
||||||
|
|
||||||
|
// Create database (separate command to ensure previous steps completed)
|
||||||
|
format!("PGPASSWORD={} ./bin/psql -h localhost -p 5432 -U gbuser -d postgres -c \"CREATE DATABASE botserver WITH OWNER gbuser\" 2>&1 | grep -v 'already exists' || true", db_password)
|
||||||
],
|
],
|
||||||
pre_install_cmds_macos: vec![],
|
pre_install_cmds_macos: vec![],
|
||||||
post_install_cmds_macos: vec![
|
post_install_cmds_macos: vec![
|
||||||
|
|
|
||||||
|
|
@ -236,13 +236,18 @@ pub mod schema {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
bots (bot_id) {
|
bots (id) {
|
||||||
bot_id -> Uuid,
|
id -> Uuid,
|
||||||
name -> Text,
|
name -> Varchar,
|
||||||
status -> Int4,
|
description -> Nullable<Text>,
|
||||||
config -> Jsonb,
|
llm_provider -> Varchar,
|
||||||
|
llm_config -> Jsonb,
|
||||||
|
context_provider -> Varchar,
|
||||||
|
context_config -> Jsonb,
|
||||||
created_at -> Timestamptz,
|
created_at -> Timestamptz,
|
||||||
updated_at -> Timestamptz,
|
updated_at -> Timestamptz,
|
||||||
|
is_active -> Nullable<Bool>,
|
||||||
|
tenant_id -> Nullable<Uuid>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue