codetether_agent/tool/
voice_stream.rs1mod actions;
7mod schema;
8
9use super::{Tool, ToolResult};
10use anyhow::{Context, Result};
11use async_trait::async_trait;
12use serde::Deserialize;
13use serde_json::Value;
14
15pub struct VoiceStreamTool {
16 client: reqwest::Client,
17}
18
19impl Default for VoiceStreamTool {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl VoiceStreamTool {
26 pub fn new() -> Self {
27 Self {
28 client: reqwest::Client::builder()
29 .timeout(std::time::Duration::from_secs(120))
30 .user_agent("CodeTether-Agent/1.0")
31 .build()
32 .expect("Failed to build HTTP client"),
33 }
34 }
35}
36
37pub(crate) fn voice_api_url() -> String {
39 std::env::var("CODETETHER_VOICE_API_URL")
40 .unwrap_or_else(|_| "https://voice.quantum-forge.io".to_string())
41}
42
43#[derive(Deserialize)]
45pub struct Params {
46 pub action: String,
47 #[serde(default)]
48 pub text: Option<String>,
49 #[serde(default)]
50 pub voice_id: Option<String>,
51 #[serde(default)]
52 pub language: Option<String>,
53 #[serde(default)]
54 pub job_id: Option<String>,
55}
56
57#[async_trait]
58impl Tool for VoiceStreamTool {
59 fn id(&self) -> &str {
60 "voice_stream"
61 }
62 fn name(&self) -> &str {
63 "VoiceStream"
64 }
65 fn description(&self) -> &str {
66 "Stream/play TTS audio in the browser. Actions: speak_stream, play."
67 }
68 fn parameters(&self) -> Value {
69 schema::json_schema()
70 }
71
72 async fn execute(&self, params: Value) -> Result<ToolResult> {
73 let p: Params = serde_json::from_value(params).context("Invalid voice_stream params")?;
74 actions::dispatch(&self.client, &p).await
75 }
76}