Files
aiturk-hermes-ide/apps/desktop/assets/codex-bridge/test_compression_settings.py
T
yilsem 91ecad8e5c
Server CI and Windows package / verify (push) Successful in 4m47s
Server CI and Windows package / windows-package (push) Successful in 8m47s
Preserve native Codex history and add configurable cross-model compression
Separate encrypted reasoning from actual compaction, stop migration after native return, and retain full history and recent exchanges. Add typed settings, Gemini fallback, verified provider windows, bounded summaries and durable concurrent checkpoints.

Validation: 245 bridge tests plus focused concurrency tests; 71 settings/connection tests; 66 supplementary tests; TypeScript checks; renderer and Electron bundles; real primary/native/fallback summary probes and 700K input acceptance.
2026-10-13 03:36:42 +03:00

171 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import copy
import json
import tempfile
import threading
import io
import time
from types import SimpleNamespace
import unittest
from concurrent.futures import ThreadPoolExecutor
from unittest.mock import patch
import compression_engine as engine
import compression_settings as cs
import gecis_context as gc
class Compression(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.store = cs.Checkpoints(self.temp.name)
self.settings = dict(cs.DEFAULTS, keepTurns=2, primaryModel='ide/primary', fallbackModel='ide/backup')
self.req = {'model': 'ide/target', 'prompt_cache_key': 'same-chat', 'input': [
{'role': 'user', 'content': 'DECISION-4827 ' + 'x' * 60000},
{'role': 'assistant', 'content': 'Done'},
{'role': 'user', 'content': 'Recent one'}, {'role': 'assistant', 'content': 'Latest answer'},
{'role': 'user', 'content': 'Recent two'}]}
self.summary = 'Amaç: DECISION-4827. Kararlar: preserve. Kısıtlar: same ID. Tamamlanan işler: done. Kalan adımlar: test. '
def tearDown(self):
self.temp.cleanup()
def test_strict_retention_never_shrinks_ten_turns_to_one(self):
req = copy.deepcopy(self.req)
settings = dict(self.settings, keepTurns=10)
with self.assertRaises(gc.TransferError):
gc.Preparer().prepare(req, 32768, lambda *_: self.fail('Must not summarize protected exchanges'), settings=settings)
self.assertEqual(req, self.req)
def test_percent_token_and_output_reserve_budgets(self):
for mode, expected in [('percent', 70000), ('tokens', 64000)]:
self.assertEqual(gc.input_budget({}, 100000, dict(self.settings, budgetMode=mode)), expected)
self.assertEqual(gc.input_budget({}, 100000, self.settings, automatic=True), 50000)
self.assertEqual(gc.input_budget({'max_output_tokens': 80000}, 100000, self.settings), 20000)
def test_boundary_equal_does_not_summarize(self):
size = gc.tokens(self.req)
settings = dict(self.settings, budgetMode='tokens', maxTokens=size)
self.assertEqual(gc.Preparer().prepare(self.req, 100000, lambda *_: self.fail('At boundary'), settings=settings), self.req)
def test_checkpoint_survives_restart_and_appended_message(self):
first = gc.Preparer().prepare(self.req, 32768, lambda *_: self.summary, 'account-chat', settings=self.settings, checkpoints=self.store)
later = copy.deepcopy(self.req)
later['input'].extend([{'role':'assistant','content':'new answer'}, {'role':'user','content':'continue'}])
second = gc.Preparer().prepare(later, 32768, lambda *_: self.fail('Should reuse saved prefix'), 'account-chat', settings=self.settings, checkpoints=cs.Checkpoints(self.temp.name))
self.assertEqual(second['prompt_cache_key'], 'same-chat')
self.assertIn('DECISION-4827', json.dumps(second))
self.assertEqual(second['input'][-1], later['input'][-1])
self.assertLessEqual(gc.tokens(first), gc.input_budget(self.req, 32768, self.settings))
def test_failed_or_oversized_summary_never_commits(self):
for text in ['', 'x' * 60000]:
with self.assertRaises(gc.TransferError):
gc.Preparer().prepare(self.req, 32768, lambda *_: text, 'scope', settings=self.settings, checkpoints=self.store)
old = gc.split_history(self.req['input'], 2)[1]
self.assertIsNone(self.store.get('scope', old, self.settings))
def test_scopes_and_changed_sources_never_share_summary(self):
old = gc.split_history(self.req['input'], 2)[1]
self.store.save('a', old, self.settings, self.summary)
self.assertIsNone(self.store.get('b', old, self.settings))
changed = copy.deepcopy(old); changed[0]['content'] = 'different'
self.assertIsNone(self.store.get('a', changed, self.settings))
def test_restore_checks_scope_and_preserves_all_versions(self):
old = [{'role':'user','content':'decision'}]
self.store.save('a', old, self.settings, 'version one')
self.store.save('a', old, self.settings, 'version two')
self.store.restore('a', 1)
self.assertEqual(self.store.get('a', old, self.settings)[1], 'version one')
with self.assertRaises(ValueError): self.store.restore('b', 1)
def test_duplicate_requests_coalesce(self):
entered, release = threading.Event(), threading.Event()
count = []
def run():
count.append(1); entered.set(); release.wait(5)
return {'value':'same'}
with ThreadPoolExecutor(2) as pool:
one = pool.submit(self.store.coalesce, 'same-key', run)
self.assertTrue(entered.wait(2))
two = pool.submit(self.store.coalesce, 'same-key', run)
# Synchronize entry under the store lock before releasing owner.
threading.Event().wait(.05)
release.set()
self.assertEqual(one.result(), two.result())
self.assertEqual(len(count), 1)
def test_fallback_sequence_and_unverified_million_rejected(self):
class Handler:
def _transfer_window(self, slug): return 1000000 if slug == 'ide/backup' else 128000
calls = []
def mock_call(_h,_m,slug,*args):
calls.append(slug)
if slug == 'ide/primary': raise TimeoutError()
return self.summary
with patch.object(engine, 'call', side_effect=mock_call):
self.assertEqual(engine.summarize(Handler(), None, '[]', 500, self.settings, 'ide/current'), self.summary)
self.assertEqual(calls, ['ide/primary', 'ide/backup'])
calls.clear()
with patch.object(engine, 'call', side_effect=mock_call):
engine.summarize(Handler(), None, '[]', 500, dict(self.settings, fallbackModel='ide/unverified'), 'ide/current')
self.assertEqual(calls, ['ide/primary', 'ide/current'])
def test_tool_pairs_cannot_be_split_between_chunks(self):
items = [{'type':'function_call','call_id':'a','arguments':'x'*500}, {'role':'user','content':'interleaved'}, {'type':'function_call_output','call_id':'a','output':'result'}]
grouped = engine.chunks(gc.encoded(items), 2000)
self.assertEqual(len(grouped), 1)
with self.assertRaises(gc.TransferError): engine.chunks(gc.encoded(items), 100)
def test_invalid_settings_fail_without_defaults(self):
for patch_value in [{'keepTurns':0}, {'targetPercent':70}, {'timeoutSeconds':0}, {'autoEnabled':'yes'}]:
with self.assertRaises(ValueError): cs.validate(dict(self.settings, **patch_value))
def test_structured_unicode_messages_and_reduce_text_split_without_loss(self):
content = 'Karar 🧭 ' * 3000
item = {'role':'user', 'content':[{'type':'input_text', 'text':content}]}
parts = [x for chunk in engine.chunks(gc.encoded([item]), 2000) for x in json.loads(chunk)]
self.assertEqual(''.join(x['content'][0]['text'] for x in parts), content)
self.assertTrue(all(gc.tokens([x]) <= 2000 for x in parts))
reduced = [x for chunk in engine.chunks(gc.encoded([content]), 2000) for x in json.loads(chunk)]
self.assertEqual(''.join(reduced), content)
def test_late_older_checkpoint_cannot_replace_newer_prefix(self):
old = [{'role':'user', 'content':'old'}]
newer = old + [{'role':'assistant', 'content':'new'}]
self.store.save('scope', newer, self.settings, 'new snapshot')
self.store.save('scope', old, self.settings, 'late old snapshot')
self.assertEqual(self.store.get('scope', newer, self.settings), (2, 'new snapshot'))
def test_late_summary_cannot_replace_edited_history_of_same_length(self):
old = [{'role':'user', 'content':'old'}]
edited = [{'role':'user', 'content':'edited'}]
self.store.begin('scope', old, self.settings)
self.store.begin('scope', edited, self.settings)
self.store.save('scope', edited, self.settings, 'edited snapshot')
self.store.save('scope', old, self.settings, 'late old snapshot')
self.assertEqual(self.store.get('scope', edited, self.settings), (1, 'edited snapshot'))
def test_tool_free_high_summary_reserves_thinking_and_requires_completion(self):
module = SimpleNamespace(ek_model_mu=lambda _: True,
MODEL_MAP={'ide/primary':('route', 'gemini-3.8-flash-high')},
ROUTES={'route':{'url':'https://example.invalid/responses', 'key':'synthetic'}}, UA='test')
handler = SimpleNamespace(_transfer_window=lambda _: 1000000)
event = {'type':'response.completed', 'response':{'output':[{'type':'message','content':[{'type':'output_text','text':self.summary}]}]}}
bodies = []
def response(request, **_kwargs):
bodies.append(json.loads(request.data))
return io.BytesIO(('data: '+json.dumps(event)+'\n\n').encode())
with patch.object(engine.urllib.request, 'urlopen', side_effect=response):
result = engine.call(handler,module,'ide/primary','["history"]',1024,self.settings,time.monotonic()+5)
self.assertEqual(result.strip(), self.summary.strip())
self.assertEqual(bodies[0]['tools'], [])
self.assertEqual(bodies[0]['tool_choice'], 'none')
self.assertEqual(bodies[0]['max_output_tokens'], 25600)
event['type'] = 'response.incomplete'
with patch.object(engine.urllib.request, 'urlopen', side_effect=response), self.assertRaises(gc.TransferError):
engine.call(handler,module,'ide/primary','["history"]',1024,self.settings,time.monotonic()+5)
if __name__ == '__main__': unittest.main()