Reserve local schema overhead for compaction

ober

8b172b896939f717fbba70e7b3a8bc77a517d854

diff --git a/src/jcode/core/agent.ss b/src/jcode/core/agent.ss
index 17d70fc..8be8d3b 100644
--- a/src/jcode/core/agent.ss
+++ b/src/jcode/core/agent.ss
@@ -314,9 +314,11 @@ Be concise. Prefer edit over write for modifying existing files.
          (mdl    (or (current-model-override) (config-ref "model") "")))
     (cond
       ((should-compact? rebuilt mdl)
-       ;; Dispatch to the configured strategy (default Tiered). Budget is the
-       ;; model's context window; should-compact? already guaranteed it is set.
-       (run-configured-compaction rebuilt (model-context-window mdl)))
+       ;; Dispatch to the configured strategy (default Tiered). Small local
+       ;; models use an effective budget that reserves fixed tool-schema
+       ;; overhead outside the message list.
+       (run-configured-compaction rebuilt
+         (effective-compaction-budget (model-context-window mdl))))
       (else rebuilt))))
 
 (def (truncated-dir)
diff --git a/src/jcode/core/compaction.ss b/src/jcode/core/compaction.ss
index 49d9a93..d9cd968 100644
--- a/src/jcode/core/compaction.ss
+++ b/src/jcode/core/compaction.ss
@@ -24,6 +24,7 @@
 
 (export compact-messages
         compaction-config
+        effective-compaction-budget
         should-compact?
         estimate-message-tokens)
 
@@ -69,10 +70,19 @@
                                       tcs))))
          (loop (cdr ms) (+ acc (string-length c) tc-bytes)))))))
 
+(def (effective-compaction-budget win)
+  "Return the message-history budget after reserving fixed prompt overhead.
+   Small local tool-calling models spend part of every request on the system
+   prompt, JSON envelope, and tool schemas; message-only estimates must leave
+   room for that overhead or compaction fires too late."
+  (cond
+    ((and win (<= win 4096)) (max 1024 (- win 1000)))
+    (else win)))
+
 (def (should-compact? messages model-id)
   (let ((auto (compaction-config 'auto))
         (pct  (compaction-config 'trigger_pct))
-        (win  (model-context-window model-id))
+        (win  (effective-compaction-budget (model-context-window model-id)))
         (est  (estimate-message-tokens messages)))
     (and auto win pct (> est 0)
          (>= (* 100 est) (* pct win)))))
diff --git a/test/run.ss b/test/run.ss
index 0f7b04d..67a98b0 100644
--- a/test/run.ss
+++ b/test/run.ss
@@ -27,6 +27,7 @@
         (jcode core errors)
         (jcode provider sampling)
         (jcode core hardware)
+        (jcode core compaction)
         (jcode core compaction-strategy)
         (jcode core workflow)
         (jcode core steps)
@@ -766,6 +767,9 @@
 ;; ── compaction strategies (Phase 4) ────────────────────────────────
 (section "=== compaction strategies ===")
 
+(check! "effective budget small reserves overhead" (effective-compaction-budget 3072) 2072)
+(check! "effective budget large unchanged" (effective-compaction-budget 128000) 128000)
+
 (define (asst-tc content)
   (make-assistant-message content (list (make-tool-call "read" "{}"))))