use std::future::Future;
use std::pin::Pin;
use zeph_commands::CommandError;
use zeph_commands::traits::debug::DebugAccess;
use zeph_commands::traits::messages::MessageAccess;
use zeph_commands::traits::session::SessionAccess;
use super::log_commands;
use super::state::{DebugState, MetricsState, ProviderState, SecurityState, ToolState};
use super::tool_orchestrator::ToolOrchestrator;
impl DebugAccess for DebugState {
fn log_status(&self) -> String {
let mut out = String::new();
log_commands::format_logging_status(&self.logging_config, &mut out);
out
}
fn read_log_tail<'a>(
&'a self,
n: usize,
) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'a>> {
let file = self.logging_config.file.clone();
Box::pin(async move {
if file.is_empty() {
return None;
}
let base = std::path::PathBuf::from(&file);
tokio::task::spawn_blocking(move || {
let actual = log_commands::resolve_current_log_file(&base);
actual.and_then(|p| log_commands::read_log_tail(&p, n))
})
.await
.unwrap_or(None)
})
}
fn scrub(&self, text: &str) -> String {
crate::redact::scrub_content(text).into_owned()
}
fn dump_status(&self) -> Option<String> {
self.debug_dumper
.as_ref()
.map(|d| d.dir().display().to_string())
}
fn dump_format_name(&self) -> String {
format!("{:?}", self.dump_format).to_lowercase()
}
fn enable_dump(&mut self, dir: &str) -> Result<String, CommandError> {
let path = std::path::PathBuf::from(dir);
match crate::debug_dump::DebugDumper::new(&path, self.dump_format) {
Ok(dumper) => {
let display = dumper.dir().display().to_string();
self.debug_dumper = Some(dumper);
Ok(display)
}
Err(e) => Err(CommandError::new(e)),
}
}
fn set_dump_format(&mut self, format_name: &str) -> Result<(), CommandError> {
let fmt = match format_name {
"json" => crate::debug_dump::DumpFormat::Json,
"raw" => crate::debug_dump::DumpFormat::Raw,
"trace" => crate::debug_dump::DumpFormat::Trace,
other => {
return Err(CommandError::new(format!(
"Unknown format '{other}'. Valid values: json, raw, trace."
)));
}
};
self.switch_format(fmt);
Ok(())
}
}
pub(super) struct MessageAccessImpl<'a> {
pub msg: &'a mut super::state::MessageState,
pub tool_state: &'a mut ToolState,
pub providers: &'a mut ProviderState,
pub metrics: &'a MetricsState,
pub security: &'a mut SecurityState,
pub tool_orchestrator: &'a mut ToolOrchestrator,
}
impl MessageAccess for MessageAccessImpl<'_> {
fn clear_history(&mut self) {
let system_prompt = self.msg.messages.first().cloned();
self.msg.messages.clear();
if let Some(sp) = system_prompt {
self.msg.messages.push(sp);
}
self.tool_state.completed_tool_ids.clear();
self.providers.cached_prompt_tokens = self
.msg
.messages
.iter()
.map(|m| self.metrics.token_counter.count_message_tokens(m) as u64)
.sum();
self.msg.pending_image_parts.clear();
self.tool_orchestrator.clear_cache();
self.security.user_provided_urls.write().clear();
}
fn queue_len(&self) -> usize {
self.msg.message_queue.len()
}
fn drain_queue(&mut self) -> usize {
let n = self.msg.message_queue.len();
self.msg.message_queue.clear();
n
}
fn notify_queue_count<'a>(
&'a mut self,
_count: usize,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async {})
}
}
pub(super) struct SessionAccessImpl {
pub supports_exit: bool,
}
impl SessionAccess for SessionAccessImpl {
fn supports_exit(&self) -> bool {
self.supports_exit
}
}
pub(super) struct NullDebugAccess;
impl zeph_commands::traits::debug::DebugAccess for NullDebugAccess {
fn log_status(&self) -> String {
String::new()
}
fn read_log_tail<'a>(
&'a self,
_n: usize,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<String>> + Send + 'a>> {
Box::pin(async { None })
}
fn scrub(&self, text: &str) -> String {
text.to_owned()
}
fn dump_status(&self) -> Option<String> {
None
}
fn dump_format_name(&self) -> String {
String::new()
}
fn enable_dump(&mut self, _dir: &str) -> Result<String, CommandError> {
Ok(String::new())
}
fn set_dump_format(&mut self, _format_name: &str) -> Result<(), CommandError> {
Ok(())
}
}
pub(super) struct NullMessageAccess;
impl zeph_commands::traits::messages::MessageAccess for NullMessageAccess {
fn clear_history(&mut self) {}
fn queue_len(&self) -> usize {
0
}
fn drain_queue(&mut self) -> usize {
0
}
fn notify_queue_count<'a>(
&'a mut self,
_count: usize,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send + 'a>> {
Box::pin(async {})
}
}
pub(super) struct NullSessionAccess;
impl SessionAccess for NullSessionAccess {
fn supports_exit(&self) -> bool {
false
}
}