fix(botserver): Handle TOOL_EXEC message type for direct tool execution without KB/LLM
Some checks failed
BotServer CI/CD / build (push) Failing after 5m40s
Some checks failed
BotServer CI/CD / build (push) Failing after 5m40s
This commit is contained in:
parent
3684c862c6
commit
86bb4cad8e
4 changed files with 128 additions and 4 deletions
|
|
@ -323,18 +323,19 @@ fn add_tool_suggestion(
|
||||||
let redis_key = format!("suggestions:{}:{}", user_session.bot_id, user_session.id);
|
let redis_key = format!("suggestions:{}:{}", user_session.bot_id, user_session.id);
|
||||||
info!("Adding suggestion to Redis key: {}", redis_key);
|
info!("Adding suggestion to Redis key: {}", redis_key);
|
||||||
|
|
||||||
// Create action object and serialize it to JSON string
|
let prompt_for_params = params.is_some() && !params.as_ref().unwrap().is_empty();
|
||||||
let action_obj = json!({
|
let action_obj = json!({
|
||||||
"type": "invoke_tool",
|
"type": "invoke_tool",
|
||||||
"tool": tool_name,
|
"tool": tool_name,
|
||||||
"params": params,
|
"params": params,
|
||||||
"prompt_for_params": params.is_none()
|
"prompt_for_params": prompt_for_params
|
||||||
});
|
});
|
||||||
let action_str = action_obj.to_string();
|
|
||||||
|
|
||||||
let suggestion = json!({
|
let suggestion = json!({
|
||||||
|
"type": "invoke_tool",
|
||||||
"text": button_text,
|
"text": button_text,
|
||||||
"action": action_str
|
"tool": tool_name,
|
||||||
|
"action": action_obj
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut conn = match get_redis_connection(cache_client) {
|
let mut conn = match get_redis_connection(cache_client) {
|
||||||
|
|
|
||||||
|
|
@ -589,6 +589,8 @@ impl ScriptService {
|
||||||
trimmed.starts_with("PARAM\t") ||
|
trimmed.starts_with("PARAM\t") ||
|
||||||
trimmed.starts_with("DESCRIPTION ") ||
|
trimmed.starts_with("DESCRIPTION ") ||
|
||||||
trimmed.starts_with("DESCRIPTION\t") ||
|
trimmed.starts_with("DESCRIPTION\t") ||
|
||||||
|
trimmed.starts_with("REM ") ||
|
||||||
|
trimmed.starts_with("REM\t") ||
|
||||||
trimmed.starts_with('\'') || // BASIC comment lines
|
trimmed.starts_with('\'') || // BASIC comment lines
|
||||||
trimmed.starts_with('#') || // Hash comment lines
|
trimmed.starts_with('#') || // Hash comment lines
|
||||||
trimmed.is_empty())
|
trimmed.is_empty())
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,102 @@ impl BotOrchestrator {
|
||||||
let session_id = Uuid::parse_str(&message.session_id)?;
|
let session_id = Uuid::parse_str(&message.session_id)?;
|
||||||
let message_content = message.content.clone();
|
let message_content = message.content.clone();
|
||||||
|
|
||||||
|
// Handle direct tool execution via TOOL_EXEC message type (invisible to user)
|
||||||
|
if message.message_type == MessageType::TOOL_EXEC {
|
||||||
|
let tool_name = message_content.trim();
|
||||||
|
if !tool_name.is_empty() {
|
||||||
|
info!("[TOOL_EXEC] Direct tool execution: {}", tool_name);
|
||||||
|
|
||||||
|
// Get bot name from bot_id
|
||||||
|
let bot_name = if let Ok(bot_uuid) = Uuid::parse_str(&message.bot_id) {
|
||||||
|
let conn = self.state.conn.get().ok();
|
||||||
|
conn.and_then(|mut db_conn| {
|
||||||
|
use crate::core::shared::models::schema::bots::dsl::*;
|
||||||
|
bots.filter(id.eq(bot_uuid))
|
||||||
|
.select(name)
|
||||||
|
.first::<String>(&mut db_conn)
|
||||||
|
.ok()
|
||||||
|
}).unwrap_or_else(|| "default".to_string())
|
||||||
|
} else {
|
||||||
|
"default".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let tool_result = ToolExecutor::execute_tool_by_name(
|
||||||
|
&self.state,
|
||||||
|
&bot_name,
|
||||||
|
tool_name,
|
||||||
|
&session_id,
|
||||||
|
&user_id,
|
||||||
|
).await;
|
||||||
|
|
||||||
|
let response_content = if tool_result.success {
|
||||||
|
tool_result.result
|
||||||
|
} else {
|
||||||
|
format!("Erro ao executar '{}': {}", tool_name, tool_result.error.unwrap_or_default())
|
||||||
|
};
|
||||||
|
|
||||||
|
let final_response = BotResponse {
|
||||||
|
bot_id: message.bot_id.clone(),
|
||||||
|
user_id: message.user_id.clone(),
|
||||||
|
session_id: message.session_id.clone(),
|
||||||
|
channel: message.channel.clone(),
|
||||||
|
content: response_content,
|
||||||
|
message_type: MessageType::BOT_RESPONSE,
|
||||||
|
stream_token: None,
|
||||||
|
is_complete: true,
|
||||||
|
suggestions: vec![],
|
||||||
|
context_name: None,
|
||||||
|
context_length: 0,
|
||||||
|
context_max_length: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = response_tx.send(final_response).await;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy: Handle direct tool invocation via __TOOL__: prefix
|
||||||
|
if message_content.starts_with("__TOOL__:") {
|
||||||
|
let tool_name = message_content.trim_start_matches("__TOOL__:").trim();
|
||||||
|
if !tool_name.is_empty() {
|
||||||
|
info!("Direct tool invocation via WS: {}", tool_name);
|
||||||
|
|
||||||
|
let tool_result = ToolExecutor::execute_tool_by_name(
|
||||||
|
&self.state,
|
||||||
|
&message.bot_id,
|
||||||
|
tool_name,
|
||||||
|
&session_id,
|
||||||
|
&user_id,
|
||||||
|
).await;
|
||||||
|
|
||||||
|
let response_content = if tool_result.success {
|
||||||
|
tool_result.result
|
||||||
|
} else {
|
||||||
|
format!("Erro ao executar tool '{}': {}", tool_name, tool_result.error.unwrap_or_default())
|
||||||
|
};
|
||||||
|
|
||||||
|
let final_response = BotResponse {
|
||||||
|
bot_id: message.bot_id.clone(),
|
||||||
|
user_id: message.user_id.clone(),
|
||||||
|
session_id: message.session_id.clone(),
|
||||||
|
channel: message.channel.clone(),
|
||||||
|
content: response_content,
|
||||||
|
message_type: MessageType::BOT_RESPONSE,
|
||||||
|
stream_token: None,
|
||||||
|
is_complete: true,
|
||||||
|
suggestions: vec![],
|
||||||
|
context_name: None,
|
||||||
|
context_length: 0,
|
||||||
|
context_max_length: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = response_tx.send(final_response).await {
|
||||||
|
error!("Failed to send tool response: {}", e);
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If a HEAR is blocking the script thread for this session, deliver the input
|
// If a HEAR is blocking the script thread for this session, deliver the input
|
||||||
// directly and return — the script continues from where it paused.
|
// directly and return — the script continues from where it paused.
|
||||||
if crate::basic::keywords::hearing::deliver_hear_input(
|
if crate::basic::keywords::hearing::deliver_hear_input(
|
||||||
|
|
@ -675,6 +771,7 @@ impl BotOrchestrator {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inject KB context for normal messages
|
||||||
if let Some(kb_manager) = self.state.kb_manager.as_ref() {
|
if let Some(kb_manager) = self.state.kb_manager.as_ref() {
|
||||||
let context = crate::core::bot::kb_context::KbInjectionContext {
|
let context = crate::core::bot::kb_context::KbInjectionContext {
|
||||||
session_id,
|
session_id,
|
||||||
|
|
|
||||||
|
|
@ -364,6 +364,30 @@ impl ToolExecutor {
|
||||||
// Fallback to source path for error messages (even if it doesn't exist)
|
// Fallback to source path for error messages (even if it doesn't exist)
|
||||||
source_path
|
source_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Execute a tool directly by name (without going through LLM)
|
||||||
|
pub async fn execute_tool_by_name(
|
||||||
|
state: &Arc<AppState>,
|
||||||
|
bot_name: &str,
|
||||||
|
tool_name: &str,
|
||||||
|
session_id: &Uuid,
|
||||||
|
user_id: &Uuid,
|
||||||
|
) -> ToolExecutionResult {
|
||||||
|
let tool_call_id = format!("direct_{}", Uuid::new_v4());
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"[TOOL_EXEC] Direct tool invocation: '{}' for bot '{}', session '{}'",
|
||||||
|
tool_name, bot_name, session_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let tool_call = ParsedToolCall {
|
||||||
|
id: tool_call_id.clone(),
|
||||||
|
tool_name: tool_name.to_string(),
|
||||||
|
arguments: Value::Object(serde_json::Map::new()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::execute_tool_call(state, bot_name, &tool_call, session_id, user_id).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue