Add agent context compaction
This commit is contained in:
@@ -39,6 +39,7 @@ pub struct Session {
|
||||
pub last_tokens_per_second: Option<f32>,
|
||||
/// Raw column value; read it through [`Session::state`].
|
||||
state: String,
|
||||
pub compacted_summary: Option<String>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
@@ -56,6 +57,7 @@ impl Session {
|
||||
context_limit: 0,
|
||||
last_tokens_per_second: None,
|
||||
state: state.as_id().to_owned(),
|
||||
compacted_summary: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +131,14 @@ struct NewMessage<'a> {
|
||||
content: &'a str,
|
||||
}
|
||||
|
||||
pub struct MessageDraft {
|
||||
pub user: bool,
|
||||
pub tool: bool,
|
||||
pub reasoning: Option<String>,
|
||||
pub reasoning_complete: bool,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProjectWithSessions {
|
||||
pub project: Project,
|
||||
@@ -391,6 +401,40 @@ impl Database {
|
||||
.map(|_| ())
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
pub fn replace_with_compacted_transcript(
|
||||
&mut self,
|
||||
session_id: i32,
|
||||
summary: &str,
|
||||
tail: &[MessageDraft],
|
||||
) -> Result<Vec<StoredMessage>, String> {
|
||||
self.connection
|
||||
.transaction(|connection| {
|
||||
diesel::delete(messages::table.filter(messages::session_id.eq(session_id)))
|
||||
.execute(connection)?;
|
||||
diesel::update(sessions::table.find(session_id))
|
||||
.set(sessions::compacted_summary.eq(Some(summary)))
|
||||
.execute(connection)?;
|
||||
let mut stored = Vec::with_capacity(tail.len());
|
||||
for message in tail {
|
||||
stored.push(
|
||||
diesel::insert_into(messages::table)
|
||||
.values(NewMessage {
|
||||
session_id,
|
||||
user: message.user,
|
||||
tool: message.tool,
|
||||
reasoning: message.reasoning.as_deref(),
|
||||
reasoning_complete: message.reasoning_complete,
|
||||
content: &message.content,
|
||||
})
|
||||
.returning(StoredMessage::as_returning())
|
||||
.get_result(connection)?,
|
||||
);
|
||||
}
|
||||
Ok(stored)
|
||||
})
|
||||
.map_err(|error: diesel::result::Error| error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -506,6 +550,29 @@ mod tests {
|
||||
assert_eq!(messages[2].content, "Tool result");
|
||||
assert!(!messages[3].user);
|
||||
assert!(!messages[3].tool);
|
||||
let compacted = reopened
|
||||
.replace_with_compacted_transcript(
|
||||
session.id,
|
||||
"Keep the active task.",
|
||||
&[MessageDraft {
|
||||
user: true,
|
||||
tool: false,
|
||||
reasoning: None,
|
||||
reasoning_complete: true,
|
||||
content: "Recent question".into(),
|
||||
}],
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(compacted.len(), 1);
|
||||
drop(reopened);
|
||||
let mut reopened = Database::open(&path).unwrap();
|
||||
assert_eq!(
|
||||
reopened.load_projects().unwrap()[0].sessions[0]
|
||||
.compacted_summary
|
||||
.as_deref(),
|
||||
Some("Keep the active task.")
|
||||
);
|
||||
assert_eq!(reopened.load_messages(session.id).unwrap().len(), 1);
|
||||
reopened.delete_session(session.id).unwrap();
|
||||
assert!(reopened.load_messages(session.id).unwrap().is_empty());
|
||||
drop(reopened);
|
||||
|
||||
Reference in New Issue
Block a user