use super::super::event_adapter::{SdkEventAdapter, ViewEvent, ViewModelEvent};
use crate::run_artifacts::AttachmentEvent;
#[cfg(test)]
pub(crate) struct SdkAttachmentWriter {
writer: crate::run_artifacts::AttachmentWriter,
adapter: SdkEventAdapter,
}
#[cfg(test)]
impl SdkAttachmentWriter {
pub(crate) fn new(
result_path: &std::path::Path,
cwd: std::path::PathBuf,
prompt: &str,
) -> anyhow::Result<Self> {
let mut writer = crate::run_artifacts::AttachmentWriter::create(result_path)?;
writer.write_event(&AttachmentEvent::Prompt(prompt.to_string()))?;
Ok(Self {
writer,
adapter: SdkEventAdapter::new(cwd),
})
}
pub(crate) fn on_event(&mut self, event: &rho_sdk::RunEvent) -> anyhow::Result<()> {
for attachment in translate_run_event(&mut self.adapter, event) {
self.writer.write_event(&attachment)?;
}
Ok(())
}
}
pub(crate) fn translate_run_event(
adapter: &mut SdkEventAdapter,
event: &rho_sdk::RunEvent,
) -> Vec<AttachmentEvent> {
adapter
.translate(event.clone())
.into_iter()
.filter_map(|view_event| match view_event {
ViewEvent::Update(update) => attachment_update(adapter, update),
ViewEvent::Notice(notice) => Some(AttachmentEvent::Notice(notice)),
ViewEvent::Questionnaire { request, .. } => Some(AttachmentEvent::Notice(format!(
"input requested but unavailable in a delegated agent: {}",
request.title()
))),
ViewEvent::Completed => {
adapter.clear_attachment_preview_keys();
Some(AttachmentEvent::Completed)
}
ViewEvent::Cancelled => {
adapter.clear_attachment_preview_keys();
Some(AttachmentEvent::Cancelled)
}
ViewEvent::Failed(message) => {
adapter.clear_attachment_preview_keys();
Some(AttachmentEvent::Failed(message))
}
})
.collect()
}
fn attachment_update(
adapter: &mut SdkEventAdapter,
update: ViewModelEvent,
) -> Option<AttachmentEvent> {
match update {
ViewModelEvent::OutputDelta(text) => Some(AttachmentEvent::AssistantTextDelta(text)),
ViewModelEvent::ReasoningDelta(text) => Some(AttachmentEvent::ReasoningDelta(text)),
ViewModelEvent::ToolStarted { call_id, card }
| ViewModelEvent::ToolCallProposed { call_id, card } => {
let key = adapter.attachment_key_for_call(&call_id);
Some(AttachmentEvent::ToolStarted {
key: Some(key),
card,
})
}
ViewModelEvent::ToolCallUpdated {
index,
call_id,
card,
} => {
let key = adapter.attachment_key_for_preview(index, call_id.as_ref());
Some(AttachmentEvent::ToolStarted {
key: Some(key),
card,
})
}
ViewModelEvent::ToolUpdated { call_id, card } => {
let key = adapter.attachment_key_for_call(&call_id);
Some(AttachmentEvent::ToolUpdated {
key: Some(key),
card,
})
}
ViewModelEvent::ToolFinished { call_id, card, .. } => {
let key = adapter.take_attachment_key_for_call(&call_id);
Some(AttachmentEvent::ToolFinished {
key: Some(key),
card,
})
}
ViewModelEvent::RunStarted => None,
ViewModelEvent::StepStarted(_) => Some(AttachmentEvent::StepStarted),
ViewModelEvent::SteeringApplied(_) => None,
ViewModelEvent::ProviderStreamReset => {
adapter.clear_attachment_preview_keys();
Some(AttachmentEvent::ProviderStreamReset)
}
ViewModelEvent::ProviderRetry => None,
ViewModelEvent::ContextUsage(usage) => Some(AttachmentEvent::ContextUsage(usage)),
ViewModelEvent::Usage(usage) => Some(AttachmentEvent::Usage(usage)),
}
}
#[cfg(test)]
#[path = "sdk_writer_tests.rs"]
mod tests;