Initial scaffold: GyanDoot v2.0 in Rust

Full Cargo workspace with 11 crates:
- gyandoot-core: Shared types, config, error types
- gyandoot-agent: Agent loop, tool execution, context compression
- gyandoot-providers: LLM provider abstraction (OpenAI, Anthropic, Ollama)
- gyandoot-memory: MemPalace persistent memory system
- gyandoot-platform: Platform adapters (Telegram, Discord, Webhook, CLI)
- gyandoot-security: Credential vault, sanitizer, threat detector
- gyandoot-kanban: Task decomposition, swarm orchestration, diagnostics
- gyandoot-subagents: Sub-agent spawning and orchestration
- gyandoot-skills: Skills discovery, loading, preprocessing, bundles
- gyandoot-profile: Multi-agent profile manager
- gyandoot-gateway: Gateway sessions, routing, access control

Plus: CLI entry point with clap, cross-platform installer script,
KANBAN.md, .gnpl/AGENTS.md

Workspace compiles clean: cargo check passes with 0 errors.
This commit is contained in:
2026-06-11 20:04:12 +05:30
commit 851c838ca5
53 changed files with 8037 additions and 0 deletions

View File

@@ -0,0 +1,138 @@
//! Telegram bot platform adapter.
use async_trait::async_trait;
use gyandoot_core::PlatformResult;
use reqwest::Client;
use tracing::{debug, error, info};
use crate::{IncomingMessage, OutgoingMessage, Platform};
/// Adapter for the Telegram Bot API.
pub struct TelegramPlatform {
bot_token: String,
client: Client,
allowed_users: Vec<i64>,
}
impl TelegramPlatform {
/// Create a new Telegram platform adapter.
pub fn new(bot_token: String, allowed_users: Vec<i64>) -> Self {
Self {
bot_token,
client: Client::new(),
allowed_users,
}
}
/// Build the Telegram API URL for a given method.
fn api_url(&self, method: &str) -> String {
format!("https://api.telegram.org/bot{}/{}", self.bot_token, method)
}
}
#[async_trait]
impl Platform for TelegramPlatform {
fn name(&self) -> &str {
"telegram"
}
async fn start(&self) -> PlatformResult<tokio::sync::mpsc::Receiver<IncomingMessage>> {
info!("Starting Telegram polling...");
let (tx, rx) = tokio::sync::mpsc::channel(100);
let bot_token = self.bot_token.clone();
let client = self.client.clone();
let allowed_users = self.allowed_users.clone();
tokio::spawn(async move {
let mut offset: i64 = 0;
loop {
let url = format!(
"https://api.telegram.org/bot{}/getUpdates?offset={}&timeout=30",
bot_token, offset
);
match client.get(&url).send().await {
Ok(response) => {
if let Ok(data) = response.json::<serde_json::Value>().await {
if let Some(results) = data["result"].as_array() {
for update in results {
let update_id = update["update_id"].as_i64().unwrap_or(0);
offset = update_id + 1;
if let Some(msg) = update.get("message") {
let chat_id = msg["chat"]["id"].as_i64().unwrap_or(0);
let text = msg["text"].as_str().unwrap_or("").to_string();
let user_id = msg["from"]["id"].as_i64().unwrap_or(0).to_string();
let username = msg["from"]["username"]
.as_str()
.unwrap_or("unknown")
.to_string();
if !allowed_users.is_empty() && !allowed_users.contains(&chat_id) {
debug!("Ignoring message from non-allowed user {}", chat_id);
continue;
}
let incoming = IncomingMessage {
platform: "telegram".to_string(),
channel_id: chat_id.to_string(),
user_id,
username,
text,
message_id: update_id.to_string(),
};
if tx.send(incoming).await.is_err() {
error!("Telegram channel closed");
return;
}
}
}
}
}
}
Err(e) => {
error!("Telegram poll error: {}", e);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
}
}
}
});
Ok(rx)
}
async fn send(&self, message: OutgoingMessage) -> PlatformResult<()> {
let chat_id: i64 = message.channel_id.parse().unwrap_or(0);
let body = serde_json::json!({
"chat_id": chat_id,
"text": message.text,
"parse_mode": "Markdown",
});
let url = self.api_url("sendMessage");
let response = self.client.post(&url).json(&body).send().await?;
if !response.status().is_success() {
error!("Telegram send failed: {}", response.status());
}
Ok(())
}
async fn send_typing(&self, channel_id: &str) -> PlatformResult<()> {
let chat_id: i64 = channel_id.parse().unwrap_or(0);
let body = serde_json::json!({
"chat_id": chat_id,
"action": "typing",
});
let url = self.api_url("sendChatAction");
self.client.post(&url).json(&body).send().await?;
Ok(())
}
async fn shutdown(&self) -> PlatformResult<()> {
info!("Telegram platform shutting down");
Ok(())
}
}