Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Commit ·
06d26aa
1
Parent(s): 950ca5c
Add deterministic pruning of old tool outputs before LLM compaction
Browse filesCo-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- agent/context_manager/manager.py +41 -0
- agent/core/agent_loop.py +1 -0
agent/context_manager/manager.py
CHANGED
|
@@ -221,10 +221,51 @@ class ContextManager:
|
|
| 221 |
|
| 222 |
return False
|
| 223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
async def compact(
|
| 225 |
self, model_name: str, tool_specs: list[dict] | None = None
|
| 226 |
) -> None:
|
| 227 |
"""Remove old messages to keep history under target size"""
|
|
|
|
|
|
|
| 228 |
if (self.context_length <= self.max_context) or not self.items:
|
| 229 |
return
|
| 230 |
|
|
|
|
| 221 |
|
| 222 |
return False
|
| 223 |
|
| 224 |
+
def prune_old_tool_outputs(self) -> None:
|
| 225 |
+
"""Stage 1 compaction: deterministically truncate old tool outputs.
|
| 226 |
+
|
| 227 |
+
For any tool message older than the last 6 messages, replace content
|
| 228 |
+
exceeding 500 chars with a short one-line summary preserving
|
| 229 |
+
tool_call_id and name.
|
| 230 |
+
"""
|
| 231 |
+
if len(self.items) <= 6:
|
| 232 |
+
return
|
| 233 |
+
|
| 234 |
+
cutoff = len(self.items) - 6
|
| 235 |
+
for i in range(cutoff - 1, -1, -1):
|
| 236 |
+
msg = self.items[i]
|
| 237 |
+
if getattr(msg, "role", None) != "tool":
|
| 238 |
+
continue
|
| 239 |
+
content = getattr(msg, "content", None) or ""
|
| 240 |
+
if len(content) <= 500:
|
| 241 |
+
continue
|
| 242 |
+
|
| 243 |
+
tool_name = getattr(msg, "name", None) or "tool"
|
| 244 |
+
preview = content[:80]
|
| 245 |
+
total = len(content)
|
| 246 |
+
|
| 247 |
+
if tool_name == "hf_jobs":
|
| 248 |
+
summary = f"[hf_jobs: {preview}... ({total} chars)]"
|
| 249 |
+
elif tool_name == "bash":
|
| 250 |
+
# Try to extract exit_code from content
|
| 251 |
+
exit_code_part = ""
|
| 252 |
+
if "exit_code" in content[:200]:
|
| 253 |
+
for line in content[:200].splitlines():
|
| 254 |
+
if "exit_code" in line:
|
| 255 |
+
exit_code_part = f"exit_code visible if present, "
|
| 256 |
+
break
|
| 257 |
+
summary = f"[bash: {exit_code_part}{preview}... ({total} chars)]"
|
| 258 |
+
else:
|
| 259 |
+
summary = f"[{tool_name}: {preview}... ({total} chars)]"
|
| 260 |
+
|
| 261 |
+
msg.content = summary
|
| 262 |
+
|
| 263 |
async def compact(
|
| 264 |
self, model_name: str, tool_specs: list[dict] | None = None
|
| 265 |
) -> None:
|
| 266 |
"""Remove old messages to keep history under target size"""
|
| 267 |
+
self.prune_old_tool_outputs()
|
| 268 |
+
|
| 269 |
if (self.context_length <= self.max_context) or not self.items:
|
| 270 |
return
|
| 271 |
|
agent/core/agent_loop.py
CHANGED
|
@@ -199,6 +199,7 @@ def _is_transient_error(error: Exception) -> bool:
|
|
| 199 |
|
| 200 |
async def _compact_and_notify(session: Session) -> None:
|
| 201 |
"""Run compaction and send event if context was reduced."""
|
|
|
|
| 202 |
old_length = session.context_manager.context_length
|
| 203 |
tool_specs = session.tool_router.get_tool_specs_for_llm()
|
| 204 |
await session.context_manager.compact(
|
|
|
|
| 199 |
|
| 200 |
async def _compact_and_notify(session: Session) -> None:
|
| 201 |
"""Run compaction and send event if context was reduced."""
|
| 202 |
+
session.context_manager.prune_old_tool_outputs()
|
| 203 |
old_length = session.context_manager.context_length
|
| 204 |
tool_specs = session.tool_router.get_tool_specs_for_llm()
|
| 205 |
await session.context_manager.compact(
|