Skip to content

feat: nudge mid-band cadence + compress rejection escalation — port omp-side fixes #45/#48 into the kernel #73

Description

@ranxianglei

Background

Two defect classes surfaced in the omp adapter (users on weak local models — vllm/qwen3.8-27b — and long agentic turns) were fixed adapter-side. Both are host-agnostic model-behavior problems; the pi adapter lacks the equivalent fixes and every adapter reimplementing them is drift. This issue tracks moving both into acp-kernel so all adapters (omp / pi / opencode) inherit them by bumping the kernel pin.

1. Mid-band nudge cadence (omp PR #45, issue #22)

Defect: the kernel's over-limit branch (usage >= maxContextLimitPct, the 75–95% pressure band from #70) applies NO growth cadence — shouldInject re-fires on every processTurn. In an agentic turn that fires dozens of LLM calls back-to-back, the nudge is injected repeatedly (observed: twice in a row within seconds at ~21% real usage; omp issue #22).

omp-side fix (adapter patch): at the injection point, re-apply the kernel's own growth floor — suppress unless the sent view grew >= growthFloor since the last nudge the model actually saw, and ROLL BACK the stamps (lastNudgeShownTokens / lastShownByTier) that processTurn already wrote for the suppressed event. Emergency (>= emergencyThresholdPct) stays unguarded by design (#70's load-bearing choice — the overflow reminder must keep firing on every call).

Kernel-side proposal: apply the same per-tier growth floor inside the over-limit branch of processTurn, so the stamps stay truthful (no adapter rollback needed). Care needed not to regress #70's arbitration: pressure-band argmax selects the tier with max effective pending; suppression must only trigger when bestPending exists but growth since last shown is below the floor — never suppress the emergency tier when usage >= emergencyThresholdPct.

2. Compress rejection escalation (omp PR #48, issue #47)

Defect: rejection feedback is a flat, identical error every time. Weak models treat it as a fresh prompt and re-issue doomed compress calls — observed 33 rejections over 48 minutes ("Total compressible content too small (95 chars, min 5000)"). The error text itself ("Combine more messages into your range(s)") reads as a retry invitation; the model obeys it and loops. Physical delivery was verified (the rejection reaches the model every turn) — this is a behavior problem, not a visibility problem.

omp-side fix: per-session rejectStreak on the runtime slot — streak >= 3 appends an explicit STOP directive to the rejection, streak >= 4 replaces the kernel detail with a short stop message (the detail itself proved to be loop fuel). Success resets to 0. omp additionally carries the streak across view-flip re-folds (its session-level bookkeeping, fold-architecture-specific — stays adapter-side).

Kernel-side proposal: add compressRejects: number to CompressionState (next to state.nudge) and export a helper, e.g. rejectionFeedback(state, baseText): string, that adapters call when formatting rejections. Success paths (applyCompression with no errors) reset it. Adapters keep ownership of WHERE the streak lives across their state lifecycle (pi sidecar: free; omp fold slot: preserved on re-fold).

Why now

  • pi (0.1.38) lacks both fixes; its users are exposed to both defect classes.
  • omp carries both as adapter patches that become dead weight once the kernel owns the semantics.
  • opencode will need the same when it catches up on kernel pins.

Acceptance (suggested)

  • kernel tests: mid-band suppression + stamp truthfulness (no rollback needed adapter-side)
  • kernel tests: escalation at 3 / suppression at 4 / reset on success
  • exported rejection helper documented in the adapter-facing API
  • migration note: adapters drop their local patches when adopting

Downstream refs: omp #45, #48, #50 (context), issues #22/#47; pi #150 (related scale fix, already shipped).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions