Compact conversation history to fit within a token budget. Strategy: 1. Always keep the first message (provides original context) 2. Always keep the last `recent_window` messages 3. Among remaining messages, classify by importance and drop lowest-value messages first 4. K
(
messages: list[Message],
max_tokens: int = DEFAULT_MAX_TOKENS,
recent_window: int = DEFAULT_RECENT_WINDOW,
provider: str = 'openai'
)
| 220 | |
| 221 | |
| 222 | def compact_history( |
| 223 | messages: list[Message], |
| 224 | max_tokens: int = DEFAULT_MAX_TOKENS, |
| 225 | recent_window: int = DEFAULT_RECENT_WINDOW, |
| 226 | provider: str = 'openai' |
| 227 | ) -> list[Message]: |
| 228 | """Compact conversation history to fit within a token budget. |
| 229 | |
| 230 | Strategy: |
| 231 | 1. Always keep the first message (provides original context) |
| 232 | 2. Always keep the last `recent_window` messages |
| 233 | 3. Among remaining messages, classify by importance and drop |
| 234 | lowest-value messages first |
| 235 | 4. Keep tool_call/tool_result pairs together |
| 236 | |
| 237 | Args: |
| 238 | messages: Full conversation history. |
| 239 | max_tokens: Maximum token budget for the history. |
| 240 | recent_window: Number of recent messages to always preserve. |
| 241 | provider: LLM provider name for token estimation. |
| 242 | |
| 243 | Returns: |
| 244 | Compacted list of messages that fits within the token budget. |
| 245 | """ |
| 246 | if not messages: |
| 247 | return messages |
| 248 | |
| 249 | # Check if we're already within budget |
| 250 | current_tokens = estimate_history_tokens(messages, provider) |
| 251 | if current_tokens <= max_tokens: |
| 252 | return messages |
| 253 | |
| 254 | total = len(messages) |
| 255 | |
| 256 | # Determine protected indices |
| 257 | protected = set() |
| 258 | |
| 259 | # Always protect the first message |
| 260 | protected.add(0) |
| 261 | |
| 262 | # Always protect the recent window |
| 263 | recent_start = max(1, total - recent_window) |
| 264 | for i in range(recent_start, total): |
| 265 | protected.add(i) |
| 266 | |
| 267 | # If protected messages alone exceed the budget, shrink the |
| 268 | # recent window until we have room for compaction candidates. |
| 269 | while recent_window > 0: |
| 270 | protected_tokens = sum( |
| 271 | estimate_message_tokens(messages[i], provider) |
| 272 | for i in protected |
| 273 | ) |
| 274 | if protected_tokens <= max_tokens: |
| 275 | break |
| 276 | recent_window -= 1 |
| 277 | recent_start = max(1, total - recent_window) |
| 278 | protected = {0} | set(range(recent_start, total)) |
| 279 |