use crate::experience::episode::Episode;
use crate::experience::guide::ExperienceGuide;
use crate::experience::store::ExperienceStore;
use crate::experience::trace::ToolTrace;
use harness_core::{Hook, Memory};
use std::sync::Arc;
pub struct ExperienceRecorder {
store: Arc<ExperienceStore>,
trace: ToolTrace,
}
impl ExperienceRecorder {
pub fn new(memory: Arc<dyn Memory>) -> Self {
Self {
store: Arc::new(ExperienceStore::new(memory)),
trace: ToolTrace::new(),
}
}
pub fn from_store(store: ExperienceStore) -> Self {
Self {
store: Arc::new(store),
trace: ToolTrace::new(),
}
}
pub fn tool_trace_hook(&self) -> Arc<dyn Hook> {
self.trace.hook()
}
pub fn guide(&self) -> ExperienceGuide {
ExperienceGuide::new(self.store.clone())
}
pub fn store(&self) -> &Arc<ExperienceStore> {
&self.store
}
pub async fn record(&self, situation: impl Into<String>, outcome: impl Into<String>) {
let ep = Episode::new(situation, outcome).with_tools(self.trace.drain());
if let Err(e) = self.store.record(&ep).await {
tracing::warn!(error = %e, "experience record failed");
}
}
pub async fn record_episode(&self, mut ep: Episode) -> Episode {
let traced = self.trace.drain();
if ep.tools.is_empty() {
ep.tools = traced;
}
if let Err(e) = self.store.record(&ep).await {
tracing::warn!(error = %e, "experience record failed");
}
ep
}
}