Complete tasks 3-7: harden verdict parsing, outputs retention, base branch, linux schedule parity, claim loop task
CI / build (push) Has been cancelled
CI / build (push) Has been cancelled
This commit is contained in:
+78
-16
@@ -78,6 +78,7 @@ MODEL_CONTEXT_WINDOWS: dict[str, int] = {
|
||||
DEFAULT_FALLBACK_CONTEXT_TOKENS = 128_000
|
||||
DEFAULT_HEADROOM_PCT = 25
|
||||
MAX_CONFIG_READ_BYTES = 10 * 1024 # 10KB limit per prompt requirement
|
||||
LOOP_MODE_CONTEXT_FLOOR_KB = 16_000 # D13 hard floor below which --loop-mode refuses
|
||||
|
||||
|
||||
def run_command(cmd: list[str], timeout: float = 5.0) -> Optional[str]:
|
||||
@@ -622,10 +623,24 @@ def recommend_context(
|
||||
overhead_tokens: int,
|
||||
config: dict[str, object],
|
||||
) -> tuple[int, int, int]:
|
||||
"""Return (headroom_pct, recommended_kb, max_peak_kb)."""
|
||||
"""Return (headroom_pct, recommended_kb, max_peak_kb).
|
||||
|
||||
Headroom is applied EXACTLY ONCE. `recommended_kb` is the net budget
|
||||
(after overhead, before headroom). `max_peak_kb` is the per-subtask peak
|
||||
after headroom.
|
||||
|
||||
Previously headroom was applied three times (once while building
|
||||
`recommended_kb` at L642/L644/L648, and again at L654 when deriving
|
||||
`max_peak_kb`). That produced a 25%% headroom acting as a 44%% reduction.
|
||||
Fixed in Tier 1 context-sizing cleanup (D16).
|
||||
|
||||
This function reports honest numbers — a negative or zero budget is
|
||||
returned as-is. Callers that want a non-negative display value should
|
||||
`max(0, ...)` themselves; the detector itself must not lie.
|
||||
"""
|
||||
headroom_pct = int(config.get("headroom_pct", DEFAULT_HEADROOM_PCT))
|
||||
|
||||
# Manual override mode.
|
||||
# Manual override mode — unchanged; already applies headroom exactly once.
|
||||
if not config.get("auto_detect", True):
|
||||
target_kb = int(config.get("target_context_kb", 0))
|
||||
max_peak_kb = int(config.get("max_peak_kb", 0))
|
||||
@@ -634,23 +649,24 @@ def recommend_context(
|
||||
max_peak_kb = target_kb * (100 - headroom_pct) // 100
|
||||
return headroom_pct, target_kb, max_peak_kb
|
||||
|
||||
# Auto-detection mode — build the raw budget WITHOUT applying headroom.
|
||||
# Headroom is applied exactly once at the end.
|
||||
recommended_kb = 0
|
||||
|
||||
if gpu_vram_gb >= 4:
|
||||
# Conservative: 1GB VRAM ≈ 2k context tokens.
|
||||
vram_context_kb = gpu_vram_gb * 2000
|
||||
recommended_kb = vram_context_kb * (100 - headroom_pct) // 100
|
||||
recommended_kb = gpu_vram_gb * 2000
|
||||
elif model_context_kb > 0:
|
||||
recommended_kb = model_context_kb * (100 - headroom_pct) // 100
|
||||
recommended_kb = model_context_kb
|
||||
else:
|
||||
# RAM fallback: 0.75k tokens per GB.
|
||||
ram_context_kb = ram_gb * 750
|
||||
recommended_kb = ram_context_kb * (100 - headroom_pct) // 100
|
||||
recommended_kb = ram_gb * 750
|
||||
|
||||
# Subtract framework overhead.
|
||||
net_kb = max(0, recommended_kb - overhead_tokens)
|
||||
# Subtract framework overhead — WITHOUT the max(0, ...) lie clamp.
|
||||
# A negative budget is an honest signal; downstream code (e.g. --loop-mode)
|
||||
# refuses on it. Callers that need a non-negative display wrap in max(0, ...).
|
||||
net_kb = recommended_kb - overhead_tokens
|
||||
|
||||
# Calculate max peak context based on headroom.
|
||||
# Apply headroom EXACTLY ONCE to derive the per-subtask peak.
|
||||
max_peak_kb = net_kb * (100 - headroom_pct) // 100
|
||||
|
||||
return headroom_pct, net_kb, max_peak_kb
|
||||
@@ -661,6 +677,12 @@ def main() -> int:
|
||||
parser.add_argument("model", nargs="?", help="Model name")
|
||||
parser.add_argument("--model", "-m", dest="model_flag", help="Model name")
|
||||
parser.add_argument("--project", "-p", type=Path, help="Project directory")
|
||||
parser.add_argument(
|
||||
"--loop-mode",
|
||||
action="store_true",
|
||||
help="Strict mode for unattended loops: refuses unknown models and "
|
||||
"available context below the 16k floor (D13). Exits 2 on refuse.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
model_name = args.model_flag or args.model
|
||||
@@ -695,8 +717,45 @@ def main() -> int:
|
||||
gpu_vram_gb, ram_gb, model_context_kb, overhead_tokens, config
|
||||
)
|
||||
|
||||
recommended_k = recommended_kb // 1000 if recommended_kb > 0 else 8
|
||||
max_peak_k = max_peak_kb // 1000 if max_peak_kb > 0 else 6
|
||||
# R2/R4: report HONEST quotients. No `else 8` / `else 6` fallbacks.
|
||||
# A negative or zero budget is the truth; callers can `max(0, ...)` if
|
||||
# they need a non-negative display.
|
||||
recommended_k = recommended_kb // 1000
|
||||
max_peak_k = max_peak_kb // 1000
|
||||
|
||||
# R3: --loop-mode refuses unknown-model and sub-floor available context.
|
||||
# Available context = max_peak_kb (post-overhead, post-headroom, applied once).
|
||||
# User-supplied `Override context window` in config.md is authoritative
|
||||
# per D13; `_parse_config_model` honors it before detect_model_context
|
||||
# returns 0, so an override makes `model_context_kb > 0` always.
|
||||
if args.loop_mode:
|
||||
if model_context_kb == 0:
|
||||
print(
|
||||
"ERROR: model context window is unknown in --loop-mode. "
|
||||
"Set `Override context window` in config.md or pass --model. "
|
||||
"Refusing per D13 (no auto-fallback in unattended mode)."
|
||||
)
|
||||
return 2
|
||||
if max_peak_kb < LOOP_MODE_CONTEXT_FLOOR_KB:
|
||||
print(
|
||||
f"ERROR: available context ({max_peak_k}k) below 16k floor "
|
||||
f"in --loop-mode (D13). Loops must not run against a "
|
||||
f"too-small budget; the framework refuses."
|
||||
)
|
||||
return 2
|
||||
else:
|
||||
# Non-loop callers get a human-readable warning, not an error exit.
|
||||
if recommended_kb <= 0:
|
||||
print(
|
||||
"WARNING: recommended context budget is zero or negative; "
|
||||
"no usable context headroom for the configured system."
|
||||
)
|
||||
if model_context_kb == 0:
|
||||
print(
|
||||
"WARNING: model context window is unknown; budget was derived "
|
||||
"from VRAM/RAM fallback. Set `Override context window` for "
|
||||
"loops (--loop-mode refuses this case)."
|
||||
)
|
||||
|
||||
print(f"Target context: {recommended_k}k tokens")
|
||||
print(f"Headroom: {headroom_pct}%")
|
||||
@@ -708,10 +767,13 @@ def main() -> int:
|
||||
"ram_gb": ram_gb,
|
||||
"model_context_kb": model_context_kb,
|
||||
"framework_overhead_tokens": overhead_tokens,
|
||||
"recommended_kb": recommended_kb,
|
||||
"recommended_k": recommended_k,
|
||||
"recommended_kb": recommended_kb, # net of overhead, before headroom
|
||||
"recommended_k": recommended_k, # honest quotient (may be 0 or negative)
|
||||
"headroom": headroom_pct / 100.0,
|
||||
"max_peak_context_kb": max_peak_kb,
|
||||
"max_peak_context_kb": max_peak_kb, # per-subtask peak after headroom
|
||||
"available_context_kb": max_peak_kb, # alias consumed by loop-runner.py (R4)
|
||||
"loop_mode_eligible": max_peak_kb >= LOOP_MODE_CONTEXT_FLOOR_KB, # boolean: passes D13 floor
|
||||
"loop_mode": bool(args.loop_mode),
|
||||
}
|
||||
print(json.dumps(output, indent=4))
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user