Add project documentation and reference materials

Include Luna AI Assistant design docs covering channels, configuration,
core architecture, memory, scheduler, and skills. Add reference docs
from OpenClaw and ZeroClaw projects, plus Mistral and OpenAI API specs.
This commit is contained in:
2026-04-04 04:14:06 +02:00
parent 969e4d6e37
commit 9929941748
39 changed files with 55467 additions and 0 deletions
@@ -0,0 +1,213 @@
# Compaction Strategy
ZeroClaw employs a dual-path conversation compaction system to manage long-running sessions. This strategy ensures the LLM maintains relevant context while staying within performance and token limits. Unlike basic history trimming, ZeroClaw uses proactive summarization to preserve state and reactive truncation to recover from context overflows.
***
## Constants
The following constants are defined in `agent/loop_.rs` and govern the default behavior of the compaction engine:
```rust
/// Default trigger for auto-compaction when non-system message count exceeds this threshold.
const DEFAULT_MAX_HISTORY_MESSAGES: usize = 50;
/// Keep this many most-recent non-system messages after compaction.
const COMPACTION_KEEP_RECENT_MESSAGES: usize = 20;
/// Safety cap for compaction source transcript passed to the summarizer.
const COMPACTION_MAX_SOURCE_CHARS: usize = 12_000;
/// Max characters retained in stored compaction summary.
const COMPACTION_MAX_SUMMARY_CHARS: usize = 2_000;
```
***
## Two Compaction Triggers
ZeroClaw implements both agent-side proactive compaction and channel-side reactive recovery.
### 1. Proactive (Agent-Side)
The `auto_compact_history()` function in `agent/loop_.rs` is called after each turn in the interactive agent loop. It operates based on message count thresholds rather than token counts.
**Process:**
1. **Threshold Check**: It counts non-system messages. If the count is less than or equal to `max_history` (default 50), it exits.
2. **Preservation**: It identifies the system prompt (the first message if the role is "system") to ensure it is never compacted.
3. **Range Calculation**: It determines how many messages to keep (`COMPACTION_KEEP_RECENT_MESSAGES`) and how many to compact.
4. **Transcript Generation**: Older messages are formatted into a plain-text transcript via `build_compaction_transcript()`.
5. **LLM Summarization**: The transcript is sent to a summarizer model with a temperature of 0.2.
6. **Injection**: The resulting summary is inserted as an assistant message prefixed with `[Compaction summary]`.
7. **Safety Fallback**: If summarization fails, it falls back to deterministic truncation via `truncate_with_ellipsis()`.
8. **Hard Trim**: `trim_history()` runs afterward to ensure the history length is strictly enforced.
### 2. Reactive (Channel-Side)
The `compact_sender_history()` function in `channels/mod.rs` provides a fallback mechanism when the LLM returns a context-window overflow error.
**Process:**
1. **Error Detection**: `is_context_window_overflow_error()` checks for 8 keyword patterns in the error string:
- "exceeds the context window"
- "context window of this model"
- "maximum context length"
- "context length exceeded"
- "too many tokens"
- "token limit exceeded"
- "prompt is too long"
- "input is too long"
2. **Aggressive Truncation**: It keeps only the last `CHANNEL_HISTORY_COMPACT_KEEP_MESSAGES` messages.
3. **Content Cap**: Each retained message is truncated to `CHANNEL_HISTORY_COMPACT_CONTENT_CHARS`.
4. **User Recovery**: The system typically asks the user to resend their last message after the history has been thinned.
***
## Summarization Prompt
The summarizer uses a specific system and user prompt pair to ensure the output is useful for future context.
**System Prompt:**
> You are a conversation compaction engine. Summarize older chat history into concise context for future turns. Preserve: user preferences, commitments, decisions, unresolved tasks, key facts. Omit: filler, repeated chit-chat, verbose tool logs. Output plain text bullet points only.
**User Prompt:**
> Summarize the following conversation history for context preservation. Keep it short (max 12 bullet points).
>
> {transcript}
**Temperature:** 0.2
***
## Helper Functions
### trim_history()
Located in `agent/loop_.rs`, this function performs a hard drain on the oldest non-system messages.
```rust
fn trim_history(history: &mut Vec<ChatMessage>, max_history: usize) {
// Nothing to trim if within limit
let has_system = history.first().map_or(false, |m| m.role == "system");
let non_system_count = if has_system {
history.len() - 1
} else {
history.len()
};
if non_system_count <= max_history {
return;
}
let start = if has_system { 1 } else { 0 };
let to_remove = non_system_count - max_history;
history.drain(start..start + to_remove);
}
```
### build_compaction_transcript()
Formats the range of messages targeted for compaction into a single string for the summarizer.
```rust
fn build_compaction_transcript(messages: &[ChatMessage]) -> String {
let mut transcript = String::new();
for msg in messages {
let role = msg.role.to_uppercase();
let _ = writeln!(transcript, "{role}: {}", msg.content.trim());
}
if transcript.chars().count() > COMPACTION_MAX_SOURCE_CHARS {
truncate_with_ellipsis(&transcript, COMPACTION_MAX_SOURCE_CHARS)
} else {
transcript
}
}
```
### apply_compaction_summary()
Splices the generated summary into the conversation history, replacing the original messages.
```rust
fn apply_compaction_summary(
history: &mut Vec<ChatMessage>,
start: usize,
compact_end: usize,
summary: &str,
) {
let summary_msg = ChatMessage::assistant(format!("[Compaction summary]\n{}", summary.trim()));
history.splice(start..compact_end, std::iter::once(summary_msg));
}
```
### Agent::trim_history()
The high-level implementation in `agent/agent.rs` handles the separation and reassembly of system messages during a trim.
```rust
fn trim_history(&mut self) {
let max = self.config.max_history_messages;
if self.history.len() <= max {
return;
}
let mut system_messages = Vec::new();
let mut other_messages = Vec::new();
for msg in self.history.drain(..) {
match &msg {
ConversationMessage::Chat(chat) if chat.role == "system" => {
system_messages.push(msg);
}
_ => other_messages.push(msg),
}
}
if other_messages.len() > max {
let drop_count = other_messages.len() - max;
other_messages.drain(0..drop_count);
}
self.history = system_messages;
self.history.extend(other_messages);
}
```
***
## Injection Format
When compaction occurs, the summary is injected back into the history as a single assistant message. This ensures that the model sees the previous context as its own earlier summary of events.
**Format:**
```text
assistant: [Compaction summary]
- Bullet point 1
- Bullet point 2
...
```
The summary replaces the exact range of messages that were sent to the summarizer, maintaining chronological integrity between the system prompt and the recent "live" messages.
***
## Configuration
The compaction behavior is influenced by the following configuration settings:
* `config.agent.max_history_messages`: The primary threshold (default 50).
* `compact_context`: A boolean flag to enable or disable the summarization logic.
* Note: Internal constants like `COMPACTION_KEEP_RECENT_MESSAGES` are currently hardcoded in `loop_.rs`.
***
## Relevance to Luna
The ZeroClaw compaction strategy provides a significant upgrade over the basic LibrarianAgent compaction currently used in Luna. Implementing this approach in Luna would address several limitations:
* **Dual-Path Robustness**: Combining proactive message-count triggers with reactive overflow recovery ensures the agent never hits an unrecoverable "context too long" state.
* **Structured Context**: Using a specific summarization prompt preserves critical state (decisions, preferences) that is often lost in simple truncation.
* **Identifiable Injection**: The `[Compaction summary]` prefix allows the model (and debugging tools) to distinguish between raw history and summarized context.
* **Threshold Management**: Moving toward the ZeroClaw constants would provide more predictable behavior in high-volume tool-call loops.
The summarization prompt text and the `apply_compaction_summary` pattern are directly compatible with Luna's [[Core]] architecture.