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 // send tool call log as .md file if any
if !self.tool_log.is_empty() { if !self.tool_log.is_empty() {
let md = self.tool_log.join("\n"); 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() { if std::fs::write(&tmp, &md).is_ok() {
let input_file = InputFile::file(std::path::Path::new(&tmp)); let input_file = InputFile::file(std::path::Path::new(&tmp));
let _ = self.bot.send_document(self.chat_id, input_file).await; 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> { 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 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); let mut req = self.bot.send_document(self.chat_id, input_file);
if !caption.is_empty() { if !caption.is_empty() {
req = req.caption(caption); req = req.caption(caption);
} }
req.await?; req.await?;
}
}
Ok(true) Ok(true)
} }
} }

View File

@@ -193,14 +193,20 @@ pub async fn run_openai_with_tools(
for tc in &tool_calls { for tc in &tool_calls {
info!(tool = %tc.name, "executing tool call"); info!(tool = %tc.name, "executing tool call");
let args_preview = truncate_at_char_boundary(&tc.arguments, 200);
let _ = output let _ = output
.status(&format!("[{}({})]", tc.name, truncate_at_char_boundary(&tc.arguments, 100))) .status(&format!("### `{}`\n```json\n{args_preview}\n```", tc.name))
.await; .await;
let result = let result =
execute_tool(&tc.name, &tc.arguments, state, output, sid, config, chat_id) execute_tool(&tc.name, &tc.arguments, state, output, sid, config, chat_id)
.await; .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!({ messages.push(serde_json::json!({
"role": "tool", "role": "tool",
"tool_call_id": tc.id, "tool_call_id": tc.id,

View File

@@ -583,6 +583,7 @@ pub async fn execute_tool(
} }
"gen_voice" => { "gen_voice" => {
let text = args["text"].as_str().unwrap_or(""); let text = args["text"].as_str().unwrap_or("");
info!("gen_voice text={:?} args={}", text, truncate_at_char_boundary(arguments, 200));
if text.is_empty() { if text.is_empty() {
return "Error: text is required".to_string(); return "Error: text is required".to_string();
} }
@@ -611,9 +612,13 @@ pub async fn execute_tool(
Ok(Ok(out)) => { Ok(Ok(out)) => {
let stderr = String::from_utf8_lossy(&out.stderr); let stderr = String::from_utf8_lossy(&out.stderr);
let stdout = String::from_utf8_lossy(&out.stdout); 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}") 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(), Err(_) => "gen_voice timeout (120s)".to_string(),
} }
} }