fix: resolve syntax errors and stabilize start.bas guard logic
All checks were successful
BotServer CI / build (push) Successful in 56s
All checks were successful
BotServer CI / build (push) Successful in 56s
This commit is contained in:
parent
d2314ce44b
commit
21e0cb09e4
1 changed files with 89 additions and 142 deletions
|
|
@ -930,6 +930,9 @@ let system_prompt = if !message.active_switchers.is_empty() {
|
||||||
.collect(),
|
.collect(),
|
||||||
switchers: Vec::new(),
|
switchers: Vec::new(),
|
||||||
context_name: None,
|
context_name: None,
|
||||||
|
context_length: 0,
|
||||||
|
context_max_length: 0,
|
||||||
|
};
|
||||||
|
|
||||||
if let Err(e) = response_tx.send(final_response).await {
|
if let Err(e) = response_tx.send(final_response).await {
|
||||||
warn!("Failed to send final response for empty content: {}", e);
|
warn!("Failed to send final response for empty content: {}", e);
|
||||||
|
|
@ -1767,19 +1770,11 @@ async fn handle_websocket(
|
||||||
bot_id,
|
bot_id,
|
||||||
bot_name_result
|
bot_name_result
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(bot_name) = 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 work_path = crate::core::shared::utils::get_work_path();
|
||||||
let start_script_path = format!("{}/{}.gbai/{}.gbdialog/start.bas", work_path, bot_name, bot_name);
|
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 or fallback to .bas
|
||||||
|
|
||||||
// Load pre-compiled .ast only (compilation happens in Drive Monitor)
|
|
||||||
let ast_path = start_script_path.replace(".bas", ".ast");
|
let ast_path = start_script_path.replace(".bas", ".ast");
|
||||||
let ast_content = match tokio::fs::read_to_string(&ast_path).await {
|
let ast_content = match tokio::fs::read_to_string(&ast_path).await {
|
||||||
Ok(content) if !content.is_empty() => content,
|
Ok(content) if !content.is_empty() => content,
|
||||||
|
|
@ -1795,11 +1790,6 @@ async fn handle_websocket(
|
||||||
};
|
};
|
||||||
|
|
||||||
if !ast_content.is_empty() {
|
if !ast_content.is_empty() {
|
||||||
info!(
|
|
||||||
"Executing start.bas for bot {} on session {}",
|
|
||||||
bot_name, session_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let state_for_start = state.clone();
|
let state_for_start = state.clone();
|
||||||
let tx_for_start = tx.clone();
|
let tx_for_start = tx.clone();
|
||||||
let bot_id_str = bot_id.to_string();
|
let bot_id_str = bot_id.to_string();
|
||||||
|
|
@ -1819,7 +1809,6 @@ async fn handle_websocket(
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(Some(mut session)) = session_result {
|
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 actual_session_id = session.id.to_string();
|
||||||
let start_bas_flag_key = format!("start_bas_executed:{}:{}", bot_id_str, actual_session_id);
|
let start_bas_flag_key = format!("start_bas_executed:{}:{}", bot_id_str, actual_session_id);
|
||||||
|
|
||||||
|
|
@ -1836,102 +1825,60 @@ async fn handle_websocket(
|
||||||
.ok();
|
.ok();
|
||||||
was_set.is_some()
|
was_set.is_some()
|
||||||
} else {
|
} else {
|
||||||
false // Safe fallback
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
true // No cache, allow execution
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
if !should_execute {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("start.bas: Found session {} for websocket session {}", session.id, session_id);
|
// Store WebSocket ID in context
|
||||||
|
|
||||||
// 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
|
|
||||||
if let serde_json::Value::Object(ref mut map) = session.context_data {
|
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()));
|
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 state_for_redis = state_for_start.clone();
|
||||||
|
|
||||||
let result = tokio::task::spawn_blocking(move || {
|
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);
|
script_service.load_bot_config_params(&state_for_start, bot_id);
|
||||||
|
script_service.run(&ast_content).map_err(|e| e.to_string())
|
||||||
match script_service.run(&ast_content) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(format!("Script execution error: {}", e)),
|
|
||||||
}
|
|
||||||
}).await;
|
}).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(Ok(())) => {
|
Ok(Ok(())) => info!("start.bas executed successfully for bot {}", bot_name),
|
||||||
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),
|
||||||
Ok(Err(e)) => {
|
|
||||||
error!("start.bas error for bot {}: {}", bot_name, e);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("start.bas task error for bot {}: {}", bot_name, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch suggestions and switchers from Redis and send to frontend
|
// Send suggestions if any
|
||||||
// Use session_id_for_redis (DB session) not session_id_str (WebSocket session) for Redis key consistency
|
let suggestions = get_suggestions(state_for_redis.cache.as_ref(), &bot_id_str, &actual_session_id);
|
||||||
let user_id_str = user_id.to_string();
|
let switchers = get_switchers(state_for_redis.cache.as_ref(), &bot_id_str, &actual_session_id);
|
||||||
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);
|
|
||||||
if !suggestions.is_empty() || !switchers.is_empty() {
|
if !suggestions.is_empty() || !switchers.is_empty() {
|
||||||
info!("Sending {} suggestions to frontend for session {}", suggestions.len(), session_id);
|
|
||||||
let response = BotResponse {
|
let response = BotResponse {
|
||||||
bot_id: bot_id_str.clone(),
|
bot_id: bot_id_str,
|
||||||
user_id: user_id_str.clone(),
|
user_id: user_id.to_string(),
|
||||||
session_id: session_id_str.clone(),
|
session_id: session_id_str,
|
||||||
channel: "Chat".to_string(),
|
channel: "Chat".to_string(),
|
||||||
content: String::new(),
|
content: String::new(),
|
||||||
message_type: MessageType::BOT_RESPONSE,
|
message_type: MessageType::BOT_RESPONSE,
|
||||||
stream_token: None,
|
|
||||||
is_complete: true,
|
is_complete: true,
|
||||||
suggestions,
|
suggestions,
|
||||||
switchers,
|
switchers,
|
||||||
context_name: None,
|
..Default::default()
|
||||||
context_length: 0,
|
|
||||||
context_max_length: 0,
|
|
||||||
};
|
};
|
||||||
let _ = tx_for_start.send(response).await;
|
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 {
|
let mut send_task = tokio::spawn(async move {
|
||||||
while let Some(response) = rx.recv().await {
|
while let Some(response) = rx.recv().await {
|
||||||
if let Ok(json_str) = serde_json::to_string(&response) {
|
if let Ok(json_str) = serde_json::to_string(&response) {
|
||||||
if sender.send(Message::Text(json_str)).await.is_err() {
|
if sender.send(Message::Text(json_str)).await.is_err() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue