use super::error::Result;
use super::r#trait::{Tool, ToolCapability, ToolExecutionContext, ToolResult};
use crate::channels::telegram::{TelegramState, cowork};
use async_trait::async_trait;
use serde_json::Value;
use std::sync::Arc;
pub struct CoworkConnectTool {
telegram_state: Arc<TelegramState>,
}
impl CoworkConnectTool {
pub fn new(telegram_state: Arc<TelegramState>) -> Self {
Self { telegram_state }
}
}
#[async_trait]
impl Tool for CoworkConnectTool {
fn name(&self) -> &str {
"cowork_connect"
}
fn description(&self) -> &str {
"Start a Telegram cowork workspace (a shared group). Generates a t.me \
deep link the user taps to create the group — the bot auto-joins and \
hands out a team invite — plus a scannable QR. Use when the user runs \
/cowork or asks to create a cowork / team / shared workspace. Works \
from the TUI and from channels."
}
fn input_schema(&self) -> Value {
serde_json::json!({
"type": "object",
"properties": {
"workspace_name": {
"type": "string",
"description": "Name for the workspace/group (ask the user if not given)."
}
},
"required": ["workspace_name"]
})
}
fn capabilities(&self) -> Vec<ToolCapability> {
vec![ToolCapability::Network]
}
fn requires_approval(&self) -> bool {
false
}
async fn execute(&self, input: Value, _context: &ToolExecutionContext) -> Result<ToolResult> {
let workspace_name = input["workspace_name"].as_str().unwrap_or("").trim();
if workspace_name.is_empty() {
return Ok(ToolResult::error(
"Provide a workspace_name for the cowork group.".into(),
));
}
let Some(bot_username) = self.telegram_state.bot_username().await else {
return Ok(ToolResult::error(
"Telegram isn't connected yet — set it up first (/onboard:channels telegram) \
so I can build the cowork link."
.into(),
));
};
let owner_id = crate::config::Config::load()
.ok()
.and_then(|c| {
c.channels
.telegram
.allowed_users
.first()
.and_then(|s| s.parse::<i64>().ok())
})
.unwrap_or(0);
let session_id = uuid::Uuid::new_v4().simple().to_string();
self.telegram_state
.start_cowork(owner_id, owner_id, session_id.clone())
.await;
self.telegram_state
.set_workspace_name(owner_id, workspace_name)
.await;
let deep_link = cowork::build_cowork_deep_link(&bot_username, &session_id);
let qr_marker = cowork::build_invite_qr(&deep_link)
.map(|(_, path)| format!("\n\n<<IMG:{}>>", path.display()))
.unwrap_or_default();
Ok(ToolResult::success(format!(
"Cowork workspace '{workspace_name}' is ready. Open this link on your phone \
(Telegram) to create the group — name it '{workspace_name}' when asked, and I'll \
auto-join and generate a team invite:\n\n{deep_link}{qr_marker}"
)))
}
}