fix: resolve syntax errors and stabilize start.bas guard logic
All checks were successful
BotServer CI / build (push) Successful in 56s

This commit is contained in:
Rodrigo Rodriguez 2026-04-30 17:14:09 -03:00
parent d2314ce44b
commit 21e0cb09e4

View file

@ -930,6 +930,9 @@ let system_prompt = if !message.active_switchers.is_empty() {
.collect(),
switchers: Vec::new(),
context_name: None,
context_length: 0,
context_max_length: 0,
};
if let Err(e) = response_tx.send(final_response).await {
warn!("Failed to send final response for empty content: {}", e);
@ -1767,19 +1770,11 @@ async fn handle_websocket(
bot_id,
bot_name_result
);
if let Some(bot_name) = bot_name_result {
// Web clients expect start.bas to execute their first screen every time they connect/reload.
// Execute unconditionally on every WebSocket connection.
let should_execute_start_bas = true;
if should_execute_start_bas {
let work_path = crate::core::shared::utils::get_work_path();
let start_script_path = format!("{}/{}.gbai/{}.gbdialog/start.bas", work_path, bot_name, bot_name);
info!("Looking for start.bas at: {}", start_script_path);
// Load pre-compiled .ast only (compilation happens in Drive Monitor)
// Load pre-compiled .ast or fallback to .bas
let ast_path = start_script_path.replace(".bas", ".ast");
let ast_content = match tokio::fs::read_to_string(&ast_path).await {
Ok(content) if !content.is_empty() => content,
@ -1795,11 +1790,6 @@ async fn handle_websocket(
};
if !ast_content.is_empty() {
info!(
"Executing start.bas for bot {} on session {}",
bot_name, session_id
);
let state_for_start = state.clone();
let tx_for_start = tx.clone();
let bot_id_str = bot_id.to_string();
@ -1819,7 +1809,6 @@ async fn handle_websocket(
};
if let Ok(Some(mut session)) = session_result {
// Unified guard for start.bas execution (shared with stream_response)
let actual_session_id = session.id.to_string();
let start_bas_flag_key = format!("start_bas_executed:{}:{}", bot_id_str, actual_session_id);
@ -1836,99 +1825,57 @@ async fn handle_websocket(
.ok();
was_set.is_some()
} else {
false // Safe fallback
false
}
} else {
true // No cache, allow execution
true
};
if !should_execute {
trace!("start.bas already executed for session {}, skipping in handle_websocket", actual_session_id);
trace!("start.bas already executed for session {}, skipping", actual_session_id);
return;
}
info!("start.bas: Found session {} for websocket session {}", session.id, session_id);
// Save session ID before session is moved into closure
let session_id_for_redis = session.id.to_string();
// Store WebSocket session_id in context so TALK can route messages correctly
// Store WebSocket ID in context
if let serde_json::Value::Object(ref mut map) = session.context_data {
map.insert("websocket_session_id".to_string(), serde_json::Value::String(session_id.to_string()));
} else {
let mut map = serde_json::Map::new();
map.insert("websocket_session_id".to_string(), serde_json::Value::String(session_id.to_string()));
session.context_data = serde_json::Value::Object(map);
}
// Clone state_for_start for use in Redis SET after execution
let state_for_redis = state_for_start.clone();
let result = tokio::task::spawn_blocking(move || {
info!("start.bas: Creating ScriptService with session.id={}", session.id);
let mut script_service = crate::basic::ScriptService::new(
state_for_start.clone(),
session.clone()
);
let mut script_service = crate::basic::ScriptService::new(state_for_start.clone(), session.clone());
script_service.load_bot_config_params(&state_for_start, bot_id);
match script_service.run(&ast_content) {
Ok(_) => Ok(()),
Err(e) => Err(format!("Script execution error: {}", e)),
}
script_service.run(&ast_content).map_err(|e| e.to_string())
}).await;
match result {
Ok(Ok(())) => {
info!("start.bas executed successfully for bot {}", bot_name);
}
Ok(Err(e)) => {
error!("start.bas error for bot {}: {}", bot_name, e);
}
Err(e) => {
error!("start.bas task error for bot {}: {}", bot_name, e);
}
Ok(Ok(())) => info!("start.bas executed successfully for bot {}", bot_name),
Ok(Err(e)) => error!("start.bas error: {}", e),
Err(e) => error!("start.bas task error: {}", e),
}
// Fetch suggestions and switchers from Redis and send to frontend
// Use session_id_for_redis (DB session) not session_id_str (WebSocket session) for Redis key consistency
let user_id_str = user_id.to_string();
let suggestions = get_suggestions(state_for_redis.cache.as_ref(), &bot_id_str, &session_id_for_redis);
let switchers = get_switchers(state_for_redis.cache.as_ref(), &bot_id_str, &session_id_for_redis);
// Send suggestions if any
let suggestions = get_suggestions(state_for_redis.cache.as_ref(), &bot_id_str, &actual_session_id);
let switchers = get_switchers(state_for_redis.cache.as_ref(), &bot_id_str, &actual_session_id);
if !suggestions.is_empty() || !switchers.is_empty() {
info!("Sending {} suggestions to frontend for session {}", suggestions.len(), session_id);
let response = BotResponse {
bot_id: bot_id_str.clone(),
user_id: user_id_str.clone(),
session_id: session_id_str.clone(),
bot_id: bot_id_str,
user_id: user_id.to_string(),
session_id: session_id_str,
channel: "Chat".to_string(),
content: String::new(),
message_type: MessageType::BOT_RESPONSE,
stream_token: None,
is_complete: true,
suggestions,
switchers,
context_name: None,
context_length: 0,
context_max_length: 0,
..Default::default()
};
let _ = tx_for_start.send(response).await;
}
}
Ok(Err(e)) => {
error!("start.bas error for bot {}: {}", bot_name, e);
}
Err(e) => {
error!("start.bas task error for bot {}: {}", bot_name, e);
}
}
}
});
}
}
} // End of if should_execute_start_bas
}
let mut send_task = tokio::spawn(async move {