@miller-tech/uap 1.131.0 → 1.132.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -158,5 +158,52 @@ class ContaminationBreakerPreservesStateTest(unittest.TestCase):
158
158
  self.assertIn("step two", blob)
159
159
 
160
160
 
161
+ class PrunerStateCarryoverTest(unittest.TestCase):
162
+ """#2 companion: the CONTEXT PRUNER (not just the contamination breaker)
163
+ must carry the plan + files-written across a drop, or a long build re-reads
164
+ its own output after every prune (observed live: `cat lib.rs` ×16)."""
165
+
166
+ def test_prune_marker_carries_written_files(self):
167
+ long = "x " * 800 # ~400 tok each — large middle, small head/tail
168
+ messages = [{"role": "user", "content": "build the org-model crate"}]
169
+ # a WRITE in the middle (will be dropped) — the breadcrumb never
170
+ # captures write actions, only tool_result reads.
171
+ messages.append({"role": "assistant", "content": [
172
+ {"type": "tool_use", "name": "Write",
173
+ "input": {"file_path": "org-model/src/person.rs"}}]})
174
+ for _ in range(6): # large read results fill the middle
175
+ messages.append({"role": "user", "content": [
176
+ {"type": "tool_result", "content": "read " + long}]})
177
+ for t in ["a", "b", "c", "d"]: # small recent tail (protected, fits)
178
+ messages.append({"role": "user", "content": t})
179
+
180
+ body = {"messages": messages}
181
+ m = ap.SessionMonitor(context_window=4000)
182
+ out = ap.prune_conversation(body, context_window=4000, monitor=m,
183
+ target_fraction=0.4, keep_last=4)
184
+ blob = "\n".join(
185
+ b if isinstance(b, str) else str(b)
186
+ for msg in out["messages"] for b in [msg.get("content", "")]
187
+ )
188
+ # the dropped Write action survives as a carryover manifest entry
189
+ self.assertIn("STATE CARRYOVER", blob)
190
+ self.assertIn("org-model/src/person.rs", blob)
191
+
192
+ def test_no_carryover_on_fresh_prune_still_prunes(self):
193
+ """A prune with no plan/writes to carry still works (breadcrumb only)."""
194
+ long = "y " * 800
195
+ messages = [{"role": "user", "content": "explore"}]
196
+ for _ in range(6):
197
+ messages.append({"role": "user", "content": [
198
+ {"type": "tool_result", "content": "read " + long}]})
199
+ for t in ["a", "b", "c", "d"]:
200
+ messages.append({"role": "user", "content": t})
201
+ m = ap.SessionMonitor(context_window=4000)
202
+ out = ap.prune_conversation({"messages": messages}, context_window=4000,
203
+ monitor=m, target_fraction=0.4, keep_last=4)
204
+ # no crash, and it did drop (fewer messages than input)
205
+ self.assertLess(len(out["messages"]), len(messages))
206
+
207
+
161
208
  if __name__ == "__main__":
162
209
  unittest.main()