#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DisplayContext {
Agent,
#[default]
Human,
}
impl DisplayContext {
#[must_use]
pub fn new_agent() -> Self {
Self::Agent
}
#[must_use]
pub fn new_human() -> Self {
Self::Human
}
#[must_use]
pub fn detect() -> Self {
if should_enable_rich() {
Self::Human
} else {
Self::Agent
}
}
#[must_use]
pub fn is_human(&self) -> bool {
matches!(self, Self::Human)
}
#[must_use]
pub fn is_agent(&self) -> bool {
matches!(self, Self::Agent)
}
}
#[must_use]
pub fn is_agent_context() -> bool {
std::env::var("MCP_CLIENT").is_ok()
|| std::env::var("CLAUDE_CODE").is_ok()
|| std::env::var("CODEX_CLI").is_ok()
|| std::env::var("CURSOR_SESSION").is_ok()
|| std::env::var("CI").is_ok()
|| std::env::var("AGENT_MODE").is_ok()
|| std::env::var("FASTMCP_PLAIN").is_ok()
|| std::env::var("NO_COLOR").is_ok()
}
#[must_use]
pub fn should_enable_rich() -> bool {
use std::io::IsTerminal;
if std::env::var("FASTMCP_PLAIN").is_ok() || std::env::var("NO_COLOR").is_ok() {
return false;
}
if std::env::var("FASTMCP_RICH").is_ok() || std::env::var("FASTMCP_FORCE_COLOR").is_ok() {
return true;
}
if is_agent_context() {
return false;
}
std::io::stderr().is_terminal()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_display_context_new_agent() {
let ctx = DisplayContext::new_agent();
assert!(ctx.is_agent());
assert!(!ctx.is_human());
}
#[test]
fn test_display_context_new_human() {
let ctx = DisplayContext::new_human();
assert!(ctx.is_human());
assert!(!ctx.is_agent());
}
#[test]
fn test_display_context_default_is_human() {
let ctx = DisplayContext::default();
assert!(ctx.is_human());
}
#[test]
fn test_display_context_equality() {
assert_eq!(DisplayContext::Agent, DisplayContext::Agent);
assert_eq!(DisplayContext::Human, DisplayContext::Human);
assert_ne!(DisplayContext::Agent, DisplayContext::Human);
}
#[test]
fn test_display_context_clone() {
let ctx = DisplayContext::Agent;
let cloned = ctx;
assert_eq!(ctx, cloned);
}
#[test]
fn test_display_context_debug() {
let ctx = DisplayContext::Agent;
let debug_str = format!("{:?}", ctx);
assert!(debug_str.contains("Agent"));
}
#[test]
fn display_context_copy_semantics() {
let ctx = DisplayContext::Agent;
let copied = ctx;
assert!(ctx.is_agent());
assert!(copied.is_agent());
}
#[test]
fn display_context_debug_human() {
let ctx = DisplayContext::Human;
let debug_str = format!("{ctx:?}");
assert!(debug_str.contains("Human"));
}
#[test]
fn detect_returns_valid_context() {
let ctx = DisplayContext::detect();
assert!(ctx.is_agent() || ctx.is_human());
}
#[test]
fn is_agent_context_and_should_enable_rich_are_consistent() {
if is_agent_context() {
let force_plain =
std::env::var("FASTMCP_PLAIN").is_ok() || std::env::var("NO_COLOR").is_ok();
let force_rich = std::env::var("FASTMCP_RICH").is_ok()
|| std::env::var("FASTMCP_FORCE_COLOR").is_ok();
if force_plain || !force_rich {
assert!(!should_enable_rich());
}
}
}
}