fix: add thinking indicator and 30s timeout to prevent deadlock
All checks were successful
BotServer CI/CD / build (push) Successful in 3m16s
All checks were successful
BotServer CI/CD / build (push) Successful in 3m16s
This commit is contained in:
parent
3ddcc5a1d1
commit
200b026efe
1 changed files with 49 additions and 24 deletions
|
|
@ -6,6 +6,7 @@ pub mod tool_context;
|
||||||
use tool_context::get_session_tools;
|
use tool_context::get_session_tools;
|
||||||
pub mod tool_executor;
|
pub mod tool_executor;
|
||||||
use tool_executor::ToolExecutor;
|
use tool_executor::ToolExecutor;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
#[cfg(feature = "llm")]
|
#[cfg(feature = "llm")]
|
||||||
use crate::core::config::ConfigManager;
|
use crate::core::config::ConfigManager;
|
||||||
|
|
||||||
|
|
@ -1047,23 +1048,32 @@ impl BotOrchestrator {
|
||||||
|
|
||||||
analysis_buffer.push_str(&chunk);
|
analysis_buffer.push_str(&chunk);
|
||||||
|
|
||||||
|
// Safety: if we've been in analysis > 30 seconds without completion, force exit
|
||||||
|
// This prevents getting stuck if model doesn't send closing tags
|
||||||
|
const ANALYSIS_TIMEOUT_SECS: u64 = 30;
|
||||||
|
static ANALYSIS_START_TIME: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
|
||||||
|
|
||||||
if !in_analysis && handler.has_analysis_markers(&analysis_buffer) {
|
if !in_analysis && handler.has_analysis_markers(&analysis_buffer) {
|
||||||
in_analysis = true;
|
in_analysis = true;
|
||||||
|
ANALYSIS_START_TIME.store(
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs(),
|
||||||
|
Ordering::SeqCst,
|
||||||
|
);
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Detected start of thinking/analysis content for model {}",
|
"Detected start of thinking/analysis content for model {}",
|
||||||
model
|
model
|
||||||
);
|
);
|
||||||
|
|
||||||
let processed = handler.process_content(&analysis_buffer);
|
// Send thinking indicator (not the filtered content!)
|
||||||
if !processed.is_empty() && processed != analysis_buffer {
|
let thinking_msg = BotResponse {
|
||||||
full_response.push_str(&processed);
|
|
||||||
|
|
||||||
let response = BotResponse {
|
|
||||||
bot_id: message.bot_id.clone(),
|
bot_id: message.bot_id.clone(),
|
||||||
user_id: message.user_id.clone(),
|
user_id: message.user_id.clone(),
|
||||||
session_id: message.session_id.clone(),
|
session_id: message.session_id.clone(),
|
||||||
channel: message.channel.clone(),
|
channel: message.channel.clone(),
|
||||||
content: processed,
|
content: "🤔 Pensando...".to_string(),
|
||||||
message_type: MessageType::BOT_RESPONSE,
|
message_type: MessageType::BOT_RESPONSE,
|
||||||
stream_token: None,
|
stream_token: None,
|
||||||
is_complete: false,
|
is_complete: false,
|
||||||
|
|
@ -1073,18 +1083,33 @@ impl BotOrchestrator {
|
||||||
context_max_length: 0,
|
context_max_length: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if response_tx.send(response).await.is_err() {
|
if response_tx.send(thinking_msg).await.is_err() {
|
||||||
warn!("Response channel closed");
|
warn!("Response channel closed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
continue; // Skip sending raw content during thinking
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check timeout
|
||||||
|
if in_analysis {
|
||||||
|
let elapsed = std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs()
|
||||||
|
- ANALYSIS_START_TIME.load(Ordering::SeqCst);
|
||||||
|
if elapsed > ANALYSIS_TIMEOUT_SECS {
|
||||||
|
warn!("Analysis timeout after {}s, forcing exit", elapsed);
|
||||||
|
in_analysis = false;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if in_analysis && handler.is_analysis_complete(&analysis_buffer) {
|
if in_analysis && handler.is_analysis_complete(&analysis_buffer) {
|
||||||
in_analysis = false;
|
in_analysis = false;
|
||||||
trace!("Detected end of thinking for model {}", model);
|
trace!("Detected end of thinking for model {}", model);
|
||||||
|
|
||||||
|
// Clear thinking indicator - we'll send empty content that frontend understands
|
||||||
|
// Actually skip this - the next content will replace the thinking indicator
|
||||||
|
|
||||||
let processed = handler.process_content(&analysis_buffer);
|
let processed = handler.process_content(&analysis_buffer);
|
||||||
if !processed.is_empty() {
|
if !processed.is_empty() {
|
||||||
full_response.push_str(&processed);
|
full_response.push_str(&processed);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue