stage20: context budgeting - per-stage token limits (planner 12k, claim 16k, contradiction 24k, synthesis 48k)
Implemented: - context_budget.py: ContextBudgetConfig (Pydantic, frozen) mit 4 Stage-Limits, validation (ge/le), get_limit(), total_max_tokens, stage_keys - context_budget.py: ContextBudgetTracker mit track_tokens(), get_usage(), is_exhausted(), reset_stage(), reset_all(), total_usage, elapsed_seconds - context_budget.py: ContextBudgetExhaustedError mit stage_name, used_tokens, limit_tokens - orchestrator.py: _track_context_tokens() Methode, context_budget_config/tracker init - orchestrator.py: context_budget_tracker property export - __init__.py: exports ContextBudgetConfig, ContextBudgetExhaustedError, ContextBudgetTracker - priority_queue.py: __aenter__/__aexit__ auf async geandert (Testfix) - test_context_budget.py: 28 Tests (DefaultConfig, TrackAccumulation, ExhaustedError, GetUsage, Reset, IsExhausted, InvalidStageNames, InvalidTokens) - test_context_budget_integration.py: 6 Tests (Orchestrator-Integration) - HANDOFF.md: Stage 20 abgeschlossen dokumentiert Tests: 34 passed (28 unit + 6 integration) + 14 performance = 48 total
This commit is contained in:
@@ -85,9 +85,15 @@ class TestPriorityLimiter:
|
||||
|
||||
def test_release_only_for_non_high(self) -> None:
|
||||
limiter = PriorityLimiter(max_concurrency=1)
|
||||
limiter.acquire(Priority.HIGH)
|
||||
limiter.release(Priority.HIGH)
|
||||
assert limiter.active_count() == 0
|
||||
|
||||
async def test():
|
||||
await limiter.acquire(Priority.HIGH)
|
||||
# HIGH release is a no-op
|
||||
limiter.release(Priority.HIGH)
|
||||
# NORMAL still not acquired, so active_count should be 0
|
||||
assert limiter.active_count() == 0
|
||||
|
||||
asyncio_run(test())
|
||||
|
||||
def test_max_concurrency_reflection(self) -> None:
|
||||
limiter = PriorityLimiter(max_concurrency=5)
|
||||
@@ -219,7 +225,7 @@ class TestLLMConcurrency:
|
||||
async def test():
|
||||
normal_done = False
|
||||
|
||||
async def slow():
|
||||
async def slow(**kwargs):
|
||||
nonlocal normal_done
|
||||
await asyncio.sleep(0.1)
|
||||
normal_done = True
|
||||
@@ -311,5 +317,10 @@ class TestAsyncContextManager:
|
||||
|
||||
def test_context_manager(self) -> None:
|
||||
limiter = PriorityLimiter(max_concurrency=1)
|
||||
asyncio_run(limiter.__aenter__())
|
||||
asyncio_run(limiter.__aexit__(None, None, None))
|
||||
|
||||
async def test():
|
||||
ctx = await limiter.__aenter__()
|
||||
assert ctx is limiter
|
||||
await limiter.__aexit__(None, None, None)
|
||||
|
||||
asyncio_run(test())
|
||||
Reference in New Issue
Block a user