send audio via send_audio/send_voice, format tool log as markdown, add gen_voice debug logging

This commit is contained in:
Fam Zheng
2026-04-11 09:58:27 +01:00
parent 2b42ca539c
commit b55ed0127c
3 changed files with 38 additions and 7 deletions

View File

@@ -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);
let mut req = self.bot.send_document(self.chat_id, input_file);
if !caption.is_empty() {
req = req.caption(caption);
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?;
}
}
req.await?;
Ok(true)
}
}

View File

@@ -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,

View File

@@ -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(),
}
}