pub mod kv;
pub mod session;
use serde::{Deserialize, Serialize};
use crate::projection::Projection;
use crate::{BranchId, BranchInfo, BranchName, Metadata, Result, Salamander};
pub use kv::KvProjection;
pub use session::{
PendingToolCall, SessionProjection, SessionState, SessionStatus, TranscriptEntry,
};
pub type AgentDb = Salamander<EventBody>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EventBody {
Put {
key: String,
value: Vec<u8>,
},
Delete {
key: String,
},
SessionStarted {
agent_id: String,
config_hash: String,
},
ModelTurn {
role: Role,
content: String,
model: String,
},
ToolCall {
call_id: String,
tool: String,
args_json: String,
},
ToolResult {
call_id: String,
ok: bool,
content: String,
},
Decision {
summary: String,
rationale: String,
},
SessionEnded {
reason: String,
},
}
impl Salamander<EventBody> {
pub fn session_view(&self, namespace: &str) -> Result<SessionProjection> {
self.session_view_on_branch(BranchId::ZERO, namespace)
}
pub fn session_view_on_branch(
&self,
branch: BranchId,
namespace: &str,
) -> Result<SessionProjection> {
let mut projection = SessionProjection::new(namespace);
self.replay_branch(branch, namespace, 0..self.head(), |event| {
projection.apply(event);
})?;
Ok(projection)
}
pub fn fork(&mut self, namespace: &str, n: u64) -> Result<BranchInfo> {
let mut metadata = Metadata::new();
metadata.insert("session_stream".into(), namespace.as_bytes().to_vec());
self.fork_branch(
BranchId::ZERO,
n,
BranchName::new(format!("{namespace}-fork-{n}"))?,
metadata,
)
}
}