Slash commands (/quit, /help) + zero compiler warnings

1. /quit and /help commands restored:
   - /quit: exits the interactive loop
   - /help: shows formatted help box with available commands & tips
   - Unknown commands get a friendly error pointing to /help
   - Slash commands intercepted before LLM processing (no token waste)

2. Zero warnings across entire workspace (13 files fixed):
   - Fixed ambiguous glob re-exports in gyandoot-core
   - Added #[allow(dead_code)] on intentional dead fields
   - Fixed unused imports, variables, and macros
   - Fixed unused assignments in subagents
   - cleaned up service.rs, profile, kanban warnings

install.sh now produces a completely clean build with zero warnings.
This commit is contained in:
2026-06-12 12:15:01 +05:30
parent 366d93443b
commit 8c9a32075d
13 changed files with 90 additions and 22 deletions

View File

@@ -25,6 +25,7 @@ use crate::context::ContextCompressor;
use crate::tools::ToolExecutor;
// ─── CLI color constants ──────────────────────────────────────────────
#[allow(dead_code)]
mod cli_color {
pub const RESET: &str = "\x1b[0m";
pub const BOLD: &str = "\x1b[1m";
@@ -143,6 +144,7 @@ pub struct AgentLoop {
sanitizer: Sanitizer,
status: Arc<Mutex<AgentStatus>>,
retry_cfg: RetryConfig,
#[allow(dead_code)]
browser_client: Option<BrowserClient>,
}
@@ -204,7 +206,7 @@ impl AgentLoop {
// ── Identity & memory injection on startup ─────────────────────
let (agent_name, agent_role, user_name, user_role) = {
let memory = self.memory.lock().await;
let (l0, _) = memory.identity_get().unwrap_or_default();
let (_l0, _) = memory.identity_get().unwrap_or_default();
// Priority: config identity > config.agent.name > defaults
let a_name = if !self.config.identity.agent_name.is_empty() {
@@ -267,7 +269,16 @@ impl AgentLoop {
// 1. Read user input
let user_input = self.read_input().await?;
// 2. Check exit conditions
// 2. Handle built-in slash commands
if user_input.starts_with('/') {
let should_quit = self.handle_command(&user_input).await;
if should_quit {
break;
}
continue;
}
// 3. Check exit conditions
if self.should_exit(&user_input) {
info!("User requested exit");
break;
@@ -619,7 +630,49 @@ impl AgentLoop {
/// Check if the user wants to exit.
fn should_exit(&self, input: &str) -> bool {
matches!(input.to_lowercase().as_str(), "exit" | "quit" | "bye")
matches!(input.to_lowercase().as_str(), "exit" | "quit" | "bye" | "/quit")
}
/// Handle a slash command. Returns true if the user wants to exit.
async fn handle_command(&self, cmd: &str) -> bool {
match cmd.to_lowercase().as_str() {
"/quit" | "/exit" => {
info!("User requested exit via slash command");
true
}
"/help" => {
println!(
"\n{bold}{cyan}╔════════════════════════════════════╗\
\n║ GyanDoot — Help ║\
\n╚════════════════════════════════════╝{reset}\n\
\n{bold}Commands:{reset}\
\n {green}»{reset} Type anything to chat with the AI\
\n {green}/quit{reset} Exit GyanDoot\
\n {green}/help{reset} Show this help message\n\
\n{bold}Tips:{reset}\
\n • Use {cyan}web_search{reset} for online queries\
\n • Use {cyan}web_browse{reset} to visit websites\
\n • Type {yellow}exit{reset}, {yellow}quit{reset}, or {yellow}bye{reset} to exit\n",
bold = cli_color::BOLD,
cyan = cli_color::BRIGHT_CYAN,
green = cli_color::GREEN,
yellow = cli_color::YELLOW,
reset = cli_color::RESET,
);
false
}
_ => {
println!(
"\n{yellow}Unknown command:{reset} {cmd}\n\
Type {green}/help{reset} for available commands.\n",
yellow = cli_color::YELLOW,
reset = cli_color::RESET,
cmd = cmd,
green = cli_color::GREEN,
);
false
}
}
}
}

View File

@@ -7,10 +7,9 @@
//! Uses the camoufox-browser daemon protocol (Unix socket IPC).
use serde_json;
use tracing::{info, warn};
use tracing::info;
use gyandoot_browser::BrowserClient;
use gyandoot_core::ToolDefinition;
use crate::tools::Tool;

View File

@@ -58,6 +58,7 @@ impl BuiltinTool {
]
}
#[allow(dead_code)]
fn name(&self) -> &'static str {
match self {
BuiltinTool::Read => "read",

View File

@@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream;
use tracing::{debug, info, warn};
use tracing::{debug, warn};
// ─── Constants ──────────────────────────────────────────────────────────
@@ -101,6 +101,7 @@ struct DaemonCommand {
/// A response from the daemon.
#[derive(Debug, Deserialize)]
struct DaemonResponse {
#[allow(dead_code)]
id: String,
success: bool,
#[serde(default)]

View File

@@ -649,6 +649,7 @@ impl ConfigLoader {
/// - Provider-specific: `GYANDOOT_OPENAI_API_KEY`, `GYANDOOT_OPENAI_MODEL`,
/// `GYANDOOT_OPENAI_BASE_URL`, `GYANDOOT_ANTHROPIC_API_KEY`, etc.
pub fn from_env(&self, config: &mut GyandootConfig) {
#[allow(unused_macros)]
macro_rules! env_opt {
($key:literal, $target:expr) => {
if let Ok(val) = std::env::var(concat!(env_prefix_str!(), $key)) {
@@ -785,7 +786,7 @@ impl ConfigLoader {
/// Convenience: load config from a single TOML file (legacy API).
pub fn load_config_from_file(path: &std::path::Path) -> anyhow::Result<AgentConfig> {
let loader = ConfigLoader::new();
let _loader = ConfigLoader::new();
let gyandoot = ConfigLoader::from_file(path)?;
Ok(AgentConfig::from(gyandoot))
}

View File

@@ -9,6 +9,13 @@ pub mod config;
pub mod error;
pub mod service;
pub use types::*;
pub use config::*;
pub use config::{
AgentConfig, AgentSection, AnthropicConfig, BrowserSection, ConfigLoader,
GatewaySection, GyandootConfig, IdentitySection,
KanbanRootConfig, MemoryRootConfig, MemorySection, OllamaConfig,
OpenAIConfig, PlatformRootConfig, PlatformSection, ProviderRootConfig,
ProvidersSection, SecurityRootConfig, SkillsRootConfig, TelegramConfig,
WebhookConfig, DiscordConfig, load_config_from_file,
};
pub use error::*;
pub use types::*;

View File

@@ -7,8 +7,8 @@
//! Templates live in the resources/ directory of the repo and are rendered
//! at install time with the actual binary path and home directory.
use std::path::{Path, PathBuf};
use tracing::{info, warn};
use std::path::PathBuf;
use tracing::info;
use crate::{AgentError, AgentResult};

View File

@@ -1,11 +1,12 @@
//! Task decomposition — breaks complex tasks into smaller subtasks.
use gyandoot_core::{KanbanResult, Priority, Task, TaskStatus};
use gyandoot_core::{KanbanResult, Task, TaskStatus};
use uuid::Uuid;
/// Decomposes a complex task into smaller, actionable subtasks.
pub struct Decomposer {
/// Maximum depth of decomposition.
#[allow(dead_code)]
max_depth: usize,
}

View File

@@ -27,6 +27,7 @@ pub struct Diagnostics {
#[derive(Debug, Clone)]
struct TaskTiming {
#[allow(dead_code)]
created_at: DateTime<Utc>,
started_at: Option<DateTime<Utc>>,
completed_at: Option<DateTime<Utc>>,

View File

@@ -2,7 +2,7 @@
use std::collections::HashMap;
use gyandoot_core::{KanbanResult, Task, TaskStatus};
use gyandoot_core::{KanbanResult, Task};
use tracing::{debug, info};
/// Manages parallel execution of tasks via a swarm of sub-agents.

View File

@@ -441,7 +441,7 @@ impl ConfigResolver {
let default_path = self.default_config_path();
if default_path.exists() {
match Self::load_profile_from_file(&default_path) {
Ok(mut profile) => {
Ok(profile) => {
if profile_name.is_empty() {
profile_name = profile.name.clone();
}

View File

@@ -29,12 +29,11 @@
//! ```
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use chrono::{DateTime, Utc};
use gyandoot_agent::agent_loop::{AgentLoop, ConversationOutput};
use gyandoot_core::{AgentConfig, AgentError, AgentStatus};
use gyandoot_agent::agent_loop::AgentLoop;
use gyandoot_core::AgentConfig;
use tokio::sync::{Mutex, Semaphore};
use tracing::{error, info, span, warn, Level};
use uuid::Uuid;
@@ -219,7 +218,7 @@ impl SubAgentWorker {
/// The worker respects max_iterations by passing a capped max_tokens
/// and managing iteration count through the system prompt directive.
pub async fn execute(&self) -> WorkerResult {
let started_at = Utc::now();
let _started_at = Utc::now();
{
let mut s = self.status.lock().await;
*s = WorkerStatus::Running;
@@ -293,7 +292,7 @@ impl SubAgentWorker {
};
}
let completed_at = Utc::now();
let _completed_at = Utc::now();
info!(
worker_id = %self.config.id,
success = %result.success,
@@ -325,8 +324,11 @@ impl SubAgentWorker {
_config: &AgentConfig,
) -> WorkerResult {
let started_at = Utc::now();
#[allow(unused_assignments)]
let mut summary = String::new();
#[allow(unused_assignments)]
let mut error_msg = None;
#[allow(unused_assignments)]
let mut iteration_count = 0;
// Build a directive message for the sub-agent
@@ -410,7 +412,7 @@ impl SubAgentWorker {
// Build a simulated ToolExecutor with filtered tools
let tool_executor = if let Some(allowed) = &self.config.allowed_tools {
let mut exec = gyandoot_agent::tools::ToolExecutor::with_defaults();
let _exec = gyandoot_agent::tools::ToolExecutor::with_defaults();
// Remove tools not in the allowed list
let names: Vec<String> = allowed.clone();
// We can't easily unregister, so we build fresh
@@ -653,7 +655,7 @@ impl SubAgentManager {
let mut w = self.workers.lock().await;
w.retain(|_, worker| {
// We can only check the current status synchronously
let status = worker.status.try_lock().map(|mut s| s.clone()).ok();
let status = worker.status.try_lock().map(|s| s.clone()).ok();
!matches!(
status,
Some(WorkerStatus::Completed { .. }) | Some(WorkerStatus::Failed(_))

View File

@@ -303,8 +303,10 @@ fn load_and_convert_config(path: &std::path::Path) -> Result<gyandoot_core::conf
model: String,
temperature: Option<f64>,
max_tokens: Option<u32>,
#[allow(dead_code)]
#[serde(default)]
merge_system: bool,
#[allow(dead_code)]
#[serde(default)]
no_tools: bool,
}