use std::sync::Arc;
use crate::config::redact::redact_text;
use crate::session::event::{Delegated, SessionEvent, ToolActivity, ToolResult};
use crate::session::views::ViewFanOut;
pub fn redact_event(event: SessionEvent, secrets: &[String]) -> SessionEvent {
if secrets.is_empty() {
return event;
}
let clean = |text: &str| redact_text(text, secrets);
let maybe = |text: &Option<String>| text.as_deref().map(clean);
match event {
SessionEvent::Post { text } => SessionEvent::Post { text: clean(&text) },
SessionEvent::Prompt {
author,
text,
id,
withdrawn,
} => SessionEvent::Prompt {
author,
text: clean(&text),
id,
withdrawn,
},
SessionEvent::Aside {
author,
text,
id,
withdrawn,
} => SessionEvent::Aside {
author,
text: clean(&text),
id,
withdrawn,
},
SessionEvent::Notice { text, level } => SessionEvent::Notice {
text: clean(&text),
level,
},
SessionEvent::Thinking { text } => SessionEvent::Thinking { text: clean(&text) },
SessionEvent::Reply { text, command } => SessionEvent::Reply {
text: clean(&text),
command: clean(&command),
},
SessionEvent::ToolResult { result } => SessionEvent::ToolResult {
result: ToolResult {
output: clean(&result.output),
..result
},
},
SessionEvent::Delegation { delegated } => SessionEvent::Delegation {
delegated: Delegated {
question: clean(&delegated.question),
answer: maybe(&delegated.answer),
refused: maybe(&delegated.refused),
..delegated
},
},
SessionEvent::Activity { line, tool } => SessionEvent::Activity {
line: clean(&line),
tool: tool.map(|tool| ToolActivity {
target: maybe(&tool.target),
..tool
}),
},
SessionEvent::Diff {
path,
added,
removed,
body,
cause,
} => SessionEvent::Diff {
path: clean(&path),
added,
removed,
body: clean(&body),
cause: maybe(&cause),
},
SessionEvent::Upload {
name,
bytes,
caption,
} => SessionEvent::Upload {
name: clean(&name),
bytes,
caption: clean(&caption),
},
SessionEvent::Waiting { text } => SessionEvent::Waiting { text: maybe(&text) },
SessionEvent::Attachment { .. }
| SessionEvent::Reaction { .. }
| SessionEvent::Usage { .. }
| SessionEvent::Busy { .. }
| SessionEvent::BeginTurn { .. }
| SessionEvent::Close { .. } => event,
}
}
pub struct Redacting {
fan: Arc<ViewFanOut>,
secrets: Vec<String>,
}
impl Redacting {
pub fn new(fan: Arc<ViewFanOut>, secrets: Vec<String>) -> Self {
Self { fan, secrets }
}
pub async fn send(&self, event: SessionEvent) {
self.fan.send(redact_event(event, &self.secrets)).await;
}
}
#[cfg(test)]
mod tests;