| 153 | |
| 154 | |
| 155 | def run( |
| 156 | system_prompt: str, |
| 157 | initial_query: str, |
| 158 | client, |
| 159 | model: str, |
| 160 | request_config: Optional[dict] = None, |
| 161 | ) -> Tuple[str, int]: |
| 162 | context_window = _get_context_window(client, model, request_config) |
| 163 | threshold = _get_config(request_config, "compact_threshold", "COMPACT_THRESHOLD", DEFAULT_THRESHOLD) |
| 164 | keep_recent = _get_config(request_config, "compact_keep_recent", "COMPACT_KEEP_RECENT", DEFAULT_KEEP_RECENT) |
| 165 | |
| 166 | token_count = estimate_tokens(initial_query) |
| 167 | budget = int(context_window * threshold) |
| 168 | |
| 169 | if token_count < budget: |
| 170 | logger.debug(f"Compact: passthrough ({token_count} tokens < {budget} budget)") |
| 171 | return initial_query, 0 |
| 172 | |
| 173 | turns = parse_tagged_conversation(initial_query) |
| 174 | if len(turns) <= keep_recent: |
| 175 | logger.debug(f"Compact: too few turns to compress ({len(turns)} <= {keep_recent})") |
| 176 | return initial_query, 0 |
| 177 | |
| 178 | split_idx = len(turns) - keep_recent |
| 179 | older_turns = turns[:split_idx] |
| 180 | recent_turns = turns[split_idx:] |
| 181 | |
| 182 | logger.info(f"Compact: compressing {len(older_turns)} older turns, keeping {len(recent_turns)} recent") |
| 183 | |
| 184 | summary, tokens_used = compress_with_llm(older_turns, system_prompt, client, model) |
| 185 | |
| 186 | if summary is None: |
| 187 | logger.warning("Compact: compression failed, returning original query") |
| 188 | return initial_query, 0 |
| 189 | |
| 190 | compressed_turns = [("user", f"[Conversation summary]:\n{summary}")] |
| 191 | compressed_turns.extend(recent_turns) |
| 192 | |
| 193 | result = reconstruct_tagged(compressed_turns) |
| 194 | new_token_count = estimate_tokens(result) |
| 195 | logger.info(f"Compact: {token_count} -> {new_token_count} tokens (used {tokens_used} for compression)") |
| 196 | |
| 197 | return result, tokens_used |