send audio via send_audio/send_voice, format tool log as markdown, add gen_voice debug logging
This commit is contained in:
@@ -124,7 +124,12 @@ impl Output for TelegramOutput {
|
||||
// send tool call log as .md file if any
|
||||
if !self.tool_log.is_empty() {
|
||||
let md = self.tool_log.join("\n");
|
||||
let tmp = format!("/tmp/noc_tools_{}.md", std::process::id());
|
||||
// extract tool names for filename
|
||||
let names: Vec<&str> = self.tool_log.iter()
|
||||
.filter_map(|s| s.strip_prefix('[')?.split('(').next())
|
||||
.collect();
|
||||
let label = if names.is_empty() { "tools".to_string() } else { names.join("_") };
|
||||
let tmp = format!("/tmp/{label}.md");
|
||||
if std::fs::write(&tmp, &md).is_ok() {
|
||||
let input_file = InputFile::file(std::path::Path::new(&tmp));
|
||||
let _ = self.bot.send_document(self.chat_id, input_file).await;
|
||||
@@ -141,12 +146,27 @@ impl Output for TelegramOutput {
|
||||
}
|
||||
|
||||
async fn send_file(&self, path: &Path, caption: &str) -> Result<bool> {
|
||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("");
|
||||
let input_file = InputFile::file(path);
|
||||
match ext {
|
||||
"ogg" | "oga" => {
|
||||
self.bot.send_voice(self.chat_id, input_file).await?;
|
||||
}
|
||||
"wav" | "mp3" | "m4a" | "flac" => {
|
||||
let mut req = self.bot.send_audio(self.chat_id, input_file);
|
||||
if !caption.is_empty() {
|
||||
req = req.caption(caption);
|
||||
}
|
||||
req.await?;
|
||||
}
|
||||
_ => {
|
||||
let mut req = self.bot.send_document(self.chat_id, input_file);
|
||||
if !caption.is_empty() {
|
||||
req = req.caption(caption);
|
||||
}
|
||||
req.await?;
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,14 +193,20 @@ pub async fn run_openai_with_tools(
|
||||
|
||||
for tc in &tool_calls {
|
||||
info!(tool = %tc.name, "executing tool call");
|
||||
let args_preview = truncate_at_char_boundary(&tc.arguments, 200);
|
||||
let _ = output
|
||||
.status(&format!("[{}({})]", tc.name, truncate_at_char_boundary(&tc.arguments, 100)))
|
||||
.status(&format!("### `{}`\n```json\n{args_preview}\n```", tc.name))
|
||||
.await;
|
||||
|
||||
let result =
|
||||
execute_tool(&tc.name, &tc.arguments, state, output, sid, config, chat_id)
|
||||
.await;
|
||||
|
||||
let result_preview = truncate_at_char_boundary(&result, 500);
|
||||
let _ = output
|
||||
.status(&format!("**Result** ({} bytes)\n```\n{result_preview}\n```\n---", result.len()))
|
||||
.await;
|
||||
|
||||
messages.push(serde_json::json!({
|
||||
"role": "tool",
|
||||
"tool_call_id": tc.id,
|
||||
|
||||
@@ -583,6 +583,7 @@ pub async fn execute_tool(
|
||||
}
|
||||
"gen_voice" => {
|
||||
let text = args["text"].as_str().unwrap_or("");
|
||||
info!("gen_voice text={:?} args={}", text, truncate_at_char_boundary(arguments, 200));
|
||||
if text.is_empty() {
|
||||
return "Error: text is required".to_string();
|
||||
}
|
||||
@@ -611,9 +612,13 @@ pub async fn execute_tool(
|
||||
Ok(Ok(out)) => {
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
warn!("gen_voice failed (exit={}): stdout={stdout} stderr={stderr}", out.status.code().unwrap_or(-1));
|
||||
format!("gen_voice failed: {stdout} {stderr}")
|
||||
}
|
||||
Ok(Err(e)) => format!("gen_voice exec error: {e}"),
|
||||
Ok(Err(e)) => {
|
||||
warn!("gen_voice exec error: {e}");
|
||||
format!("gen_voice exec error: {e}")
|
||||
}
|
||||
Err(_) => "gen_voice timeout (120s)".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user