fix(llm): graceful degradation when compact-2026-01-12 beta header is rejected#1701
Merged
fix(llm): graceful degradation when compact-2026-01-12 beta header is rejected#1701
Conversation
- Add `ContextManagement` request field and `compact-2026-01-12` beta header to all Claude request bodies when `server_compaction = true` - Make SSE parser stateful with `ClaudeSseState` (via async-stream) to accumulate multi-event `compaction` content blocks - Add `StreamChunk::Compaction` and `MessagePart::Compaction` variants for round-trip fidelity; `take_compaction_summary()` added to `LlmProvider` trait - C2: agent loop (native + legacy streaming) prunes old messages and inserts synthetic `MessagePart::Compaction` assistant turn on compaction event - S1: `maybe_compact` and `maybe_proactive_compress` early-return when `server_compaction_active` to avoid duplicate compaction - Add `server_compaction_events` metric, `--server-compaction` CLI flag, `--init` wizard prompt, and `# server_compaction = false` in default.toml - Extend `debug_dump`, `token_counter`, and `MetricsSnapshot` for new variant Closes #1626
…eview - CRIT-1: add 95% safety fallback in maybe_compact/maybe_proactive_compress; client-side compaction no longer unconditionally skipped when server compaction is active — fires only when tokens exceed 95% of budget - SEC-COMPACT-01: sanitize compaction summary via ContentSanitizer (McpResponse/ExternalUntrusted) before inserting into context in both native and legacy tool execution paths - SEC-COMPACT-02: cap SSE compaction accumulation buffer at 32 KiB; excess bytes discarded with a warning log - IMP-3: wire server_compaction through ACP path — add server_compaction field to SharedAgentDeps, initialize from config, pass to agent builder - IMP-4: TUI integration — [SC: N] status bar indicator when server_compaction_events > 0; Compacting context (server-side)... spinner in native and legacy paths; /compaction:status command palette entry with ServerCompactionStatus TuiCommand - IMP-5 (already fixed in prior commit): context_window * 80 / 100 integer arithmetic preserved - Add ~25 unit tests across sse.rs, claude.rs, provider.rs, config/tests.rs covering compaction sequence, 32 KiB cap, serialization, beta header, take_compaction_summary, and TOML config parsing
… rejected When the Claude API rejects the compact-2026-01-12 beta header (deprecated or removed), ClaudeProvider now detects the 400 response, sets a shared Arc<AtomicBool> flag, and returns LlmError::BetaHeaderRejected instead of entering an unrecoverable error loop. Subsequent requests automatically omit the beta header and context_management field. The native tool-use retry loop (call_chat_with_tools_retry) catches BetaHeaderRejected, disables server_compaction_active on the agent, and retries the turn with client-side compaction — losing at most one turn. Detection covers all request paths: send_request, send_stream_request, chat_with_tools, and chat_typed (schema feature). The Arc ensures all ClaudeProvider clones (e.g. router replicas) observe the rejection immediately. Closes #1698 (SEC-COMPACT-03)
Resolve conflicts in CHANGELOG.md, config/default.toml, crates/zeph-core/src/bootstrap/tests.rs, crates/zeph-core/src/config/types.rs, crates/zeph-llm/src/claude.rs, and src/init.rs. Both sets of changes are preserved: - server_compaction + graceful degradation (this branch) - enable_extended_context / COV-03 test (main)
…on-w Resolve conflict in crates/zeph-llm/src/claude.rs after PR #1696 (Claude server-side compaction) was merged into main. Our graceful-degradation additions (server_compaction_rejected Arc<AtomicBool>, is_compact_beta_rejection, is_server_compaction_rejected, detection in all request paths, SEC-COMPACT-03 tests) are preserved on top of main's state.
This was referenced Mar 13, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LlmError::BetaHeaderRejectedvariant returned when the Claude API rejects thecompact-2026-01-12beta header with a 400 (unknown/invalid beta)ClaudeProvidersets a sharedArc<AtomicBool>(server_compaction_rejected) flag on detection; subsequent requests automatically omit the header andcontext_managementfieldcall_chat_with_tools_retry) catchesBetaHeaderRejected, disablesserver_compaction_activeon the agent, and retries the turn with client-side compaction — user loses at most one turnsend_request,send_stream_request,chat_with_tools,chat_typedArcensures allClaudeProviderclones (e.g. router replicas) observe the rejection immediatelyFixes #1698. Follow-up to #1696 (SEC-COMPACT-03).
Test plan
zeph-llm:is_compact_beta_rejection_*,beta_header_excluded_after_rejection,context_management_absent_after_rejection,clone_shares_rejection_flagzeph-core::agent::error:agent_error_detects_beta_header_rejectedzeph-llm::error:beta_header_rejected_is_detected,beta_header_rejected_display