Skip to main content

goose_context_management/
lib.rs

1//! Conversation compaction: summarizing a message history down to a single
2//! message so a conversation can continue past a model's context window.
3//!
4//! Three layers, smallest first:
5//!
6//! * [`summarize`] - given a model and messages, produce one summary message.
7//! * [`compact`] - the trait-based API ([`CompactionInput`] /
8//!   [`CompactionOutput`]) letting a caller read from and write back to its own
9//!   conversation representation. Rust only.
10//!
11//! Cross-language (Python/Kotlin) access is exposed by `goose-sdk`, which
12//! wraps this crate in its uniffi bindings.
13
14pub mod format;
15pub mod model;
16pub mod provider;
17pub mod structured;
18pub mod summarize;
19pub mod templates;
20
21use anyhow::Result;
22use goose_provider_types::conversation::message::Message;
23use goose_provider_types::conversation::token_usage::ProviderUsage;
24
25pub use format::format_message_for_compacting;
26pub use model::{CompactionModel, ProviderModel, TokenEstimator};
27pub use provider::CompactingProvider;
28pub use structured::{FileActivity, StructuredSummary};
29pub use summarize::{summarize, Summary};
30pub use templates::Templates;
31
32pub const DEFAULT_COMPACTION_THRESHOLD: f64 = 0.8;
33
34/// Everything compaction reads from the caller's conversation.
35pub trait CompactionInput {
36    fn messages(&self) -> Vec<Message>;
37
38    fn templates(&self) -> Templates {
39        Templates::default()
40    }
41}
42
43/// Where compaction writes its result back into the caller's conversation.
44pub trait CompactionOutput {
45    fn set_summary(&mut self, summary: Message);
46    fn set_usage(&mut self, usage: ProviderUsage);
47}
48
49pub async fn compact<I, O>(
50    model: &dyn CompactionModel,
51    estimator: Option<&dyn TokenEstimator>,
52    input: &I,
53    output: &mut O,
54) -> Result<()>
55where
56    I: CompactionInput + ?Sized,
57    O: CompactionOutput + ?Sized,
58{
59    let templates = input.templates();
60    let summary = summarize(model, estimator, &templates, &input.messages()).await?;
61    output.set_summary(summary.message);
62    output.set_usage(summary.usage);
63    Ok(())
64}
65
66impl CompactionInput for Vec<Message> {
67    fn messages(&self) -> Vec<Message> {
68        self.clone()
69    }
70}