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);
|
||||
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!({
|
||||
"type": "invoke_tool",
|
||||
"tool": tool_name,
|
||||
"params": params,
|
||||
"prompt_for_params": params.is_none()
|
||||
"prompt_for_params": prompt_for_params
|
||||
});
|
||||
let action_str = action_obj.to_string();
|
||||
|
||||
let suggestion = json!({
|
||||
"type": "invoke_tool",
|
||||
"text": button_text,
|
||||
"action": action_str
|
||||
"tool": tool_name,
|
||||
"action": action_obj
|
||||
});
|
||||
|
||||
let mut conn = match get_redis_connection(cache_client) {
|
||||
|
|
|
|||
|
|
@ -589,6 +589,8 @@ impl ScriptService {
|
|||
trimmed.starts_with("PARAM\t") ||
|
||||
trimmed.starts_with("DESCRIPTION ") ||
|
||||
trimmed.starts_with("DESCRIPTION\t") ||
|
||||
trimmed.starts_with("REM ") ||
|
||||
trimmed.starts_with("REM\t") ||
|
||||
trimmed.starts_with('\'') || // BASIC comment lines
|
||||
trimmed.starts_with('#') || // Hash comment lines
|
||||
trimmed.is_empty())
|
||||
|
|
|
|||
|
|
@ -448,6 +448,102 @@ impl BotOrchestrator {
|
|||
let session_id = Uuid::parse_str(&message.session_id)?;
|
||||
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
|
||||
// directly and return — the script continues from where it paused.
|
||||
if crate::basic::keywords::hearing::deliver_hear_input(
|
||||
|
|
@ -675,6 +771,7 @@ impl BotOrchestrator {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
// Inject KB context for normal messages
|
||||
if let Some(kb_manager) = self.state.kb_manager.as_ref() {
|
||||
let context = crate::core::bot::kb_context::KbInjectionContext {
|
||||
session_id,
|
||||
|
|
|
|||
|
|
@ -364,6 +364,30 @@ impl ToolExecutor {
|
|||
// Fallback to source path for error messages (even if it doesn't exist)
|
||||
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)]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue