Skeleton for the Coding Agent. (#1)
Reviewed-on: #1 Co-authored-by: Drew Galbraith <drew@tiramisu.one> Co-committed-by: Drew Galbraith <drew@tiramisu.one>
This commit is contained in:
parent
42e3ddacc2
commit
5d213b43d3
15 changed files with 5071 additions and 12 deletions
89
src/core/history.rs
Normal file
89
src/core/history.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use crate::core::types::ConversationMessage;
|
||||
|
||||
/// The in-memory conversation history for the current session.
|
||||
///
|
||||
/// Stores messages as a flat ordered list. Each [`push`][`Self::push`] appends
|
||||
/// one message; [`messages`][`Self::messages`] returns a slice over all of them.
|
||||
///
|
||||
/// This is a flat list for Phase 1. Phases 3+ will introduce a tree structure
|
||||
/// (each event carrying a `parent_id`) to support conversation branching and
|
||||
/// sub-agent threads. The flat model is upward-compatible: a tree is just a
|
||||
/// linear chain of parent IDs when there is no branching.
|
||||
pub struct ConversationHistory {
|
||||
messages: Vec<ConversationMessage>,
|
||||
}
|
||||
|
||||
impl ConversationHistory {
|
||||
/// Create an empty history.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
messages: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Append one message to the end of the history.
|
||||
pub fn push(&mut self, message: ConversationMessage) {
|
||||
self.messages.push(message);
|
||||
}
|
||||
|
||||
/// Return the full ordered message list, oldest-first.
|
||||
///
|
||||
/// This slice is what gets serialised and sent to the provider on each
|
||||
/// turn -- the provider needs the full prior context to generate a coherent
|
||||
/// continuation.
|
||||
pub fn messages(&self) -> &[ConversationMessage] {
|
||||
&self.messages
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ConversationHistory {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::types::Role;
|
||||
|
||||
#[test]
|
||||
fn new_history_is_empty() {
|
||||
let history = ConversationHistory::new();
|
||||
assert!(history.messages().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_and_read_roundtrip() {
|
||||
let mut history = ConversationHistory::new();
|
||||
history.push(ConversationMessage {
|
||||
role: Role::User,
|
||||
content: "hello".to_string(),
|
||||
});
|
||||
history.push(ConversationMessage {
|
||||
role: Role::Assistant,
|
||||
content: "hi there".to_string(),
|
||||
});
|
||||
|
||||
let msgs = history.messages();
|
||||
assert_eq!(msgs.len(), 2);
|
||||
assert_eq!(msgs[0].role, Role::User);
|
||||
assert_eq!(msgs[0].content, "hello");
|
||||
assert_eq!(msgs[1].role, Role::Assistant);
|
||||
assert_eq!(msgs[1].content, "hi there");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn messages_preserves_insertion_order() {
|
||||
let mut history = ConversationHistory::new();
|
||||
for i in 0u32..5 {
|
||||
history.push(ConversationMessage {
|
||||
role: Role::User,
|
||||
content: format!("msg {i}"),
|
||||
});
|
||||
}
|
||||
for (i, msg) in history.messages().iter().enumerate() {
|
||||
assert_eq!(msg.content, format!("msg {i}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue