Skip to main content

ReductionPolicy

Struct ReductionPolicy 

Source
pub struct ReductionPolicy {
Show 28 fields pub tool_output_keep_bytes: usize, pub tool_output_trigger_bytes: usize, pub protect_last_n_tool_results: usize, pub elide_stale_reads: bool, pub redact_images: bool, pub image_redact_min_bytes: usize, pub clear_turns_older_than: Option<usize>, pub read_freshness: ReadFreshness, pub diff_rereads: bool, pub diff_max_percent: u32, pub protect_imported_prefix: Option<usize>, pub elide_tool_inputs: bool, pub tool_input_trigger_bytes: usize, pub tool_input_elidable_fields: HashMap<String, String>, pub normalize_terminal_output: bool, pub terminal_output_min_savings: usize, pub duplicate_output_min_bytes: usize, pub deduplicate_outputs: bool, pub supersede_enabled: bool, pub supersede_protect_last_n: usize, pub supersede_min_bytes: usize, pub supersede_command_fields: HashMap<String, String>, pub prune_errored_inputs: bool, pub errored_input_prune_after_turns: usize, pub summarize_cleared_turns: bool, pub expected_summary_bytes: usize, pub summary_cost_floor_multiple: usize, pub cleared_turns_summary: Option<PreparedClearSummary>,
}
Expand description

Knobs controlling project_messages. Defaults match SPEC.md A5/A7, stacked per D14 with the levers that don’t need an external I/O probe to be safe on-by-default (redact_images; contrast elide_stale_reads, below).

elide_stale_reads (A8) and clear_turns_older_than (A10) are plumbed through the struct but inert by default — elide_stale_reads needs a freshness probe (probe_read_freshness) to mean anything, and clear_turns_older_than is populated per-agent from compact_after_messages (Agent::maybe_compact), not from this default.

Fields§

§tool_output_keep_bytes: usize

Bytes kept from the front of an oversized tool result (A7). Default 4096.

§tool_output_trigger_bytes: usize

Only tool results strictly larger than this are truncation candidates (A7). Default 8192.

§protect_last_n_tool_results: usize

Never reduce the newest N tool results (#1 “keep”). Default 3.

§elide_stale_reads: bool

A8 — gate for stale-file-read elision. Consults Self::read_freshness for the actual per-message verdicts; setting this without ever populating read_freshness (via probe_read_freshness) elides nothing, since the empty default freshness map treats every read as not-yet-verified.

§redact_images: bool

A9 — gate for data: URL image redaction. Default true (D14: reduced mode stacks every lossless lever on together) — unlike elide_stale_reads, this rule is a pure function of the message content already in view, so it carries none of A8’s “meaningless without a probe” caveat and can safely default on.

§image_redact_min_bytes: usize

A9 — minimum byte length of a candidate image_url part’s url string for it to become a redaction candidate; inert unless redact_images is set. Default 8192 (mirrors tool_output_trigger_bytes’s scale: small inline icons stay in view, real screenshots/photos get redacted).

§clear_turns_older_than: Option<usize>

A10 — inert until turn-clearing lands.

§read_freshness: ReadFreshness

A8 — the disk-probe pre-pass’s output (probe_read_freshness), consulted by project_messages only when Self::elide_stale_reads is set. This is data, not a config knob: it is meant to be recomputed by the caller before every project/project_messages call (disk state can change turn to turn) — project_messages itself never performs the I/O; that happens once, up front, in probe_read_freshness. Default: empty (fails closed — nothing is considered fresh without an accompanying probe).

§diff_rereads: bool

TR-3 (T26) — gate for diff-only re-read representation (ReductionKind::FileReadDiffed). Like redact_images (and unlike elide_stale_reads), this rule is a pure function of the message content already in view — a re-read’s content compared against the prior read of the same path recorded in log.read_log — with no disk-probe caveat, so it can safely default on. Default true.

§diff_max_percent: u32

TR-3 — a candidate diff must be no more than this percentage of the full re-read’s size to replace it; otherwise the full re-read stays untouched (SPEC.md TR-3 dev/03’s “large-change guard”). An integer percentage (rather than a float) so ReductionPolicy keeps its Eq derive (f64 has none). Default 50 (“diff ≤ 50% of full content”).

§protect_imported_prefix: Option<usize>

B7 coordination clamp: when an imported-prefix cache plan is active, the count of leading messages (of the slice passed to project_messages) that make up the imported session prefix. A10 turn-clearing must never establish a clear range that dips into them, since doing so would bust the prefix’s cache breakpoint (and its fidelity). None (the default) applies no clamp, matching today’s behavior for callers that never set a cache plan. Set by a runtime agent from its own imported_prefix_len, not a user-facing knob.

§elide_tool_inputs: bool

TR-10 — gate for tool-INPUT elision (ReductionKind::ToolInputElided). Default true. Unlike elide_stale_reads, the candidate rule (executed successfully + oversized payload + a disk-persisting tool) is a pure function of the view plus Self::tool_input_elidable_fields — no external disk probe is needed to decide elision itself (a probe only matters later, for the freshness-matrix ESCALATION decision, see probe_tool_input_fresh) — so, like redact_images, this can safely default on (D14: reduced mode stacks every lossless lever together).

§tool_input_trigger_bytes: usize

TR-10 — only a candidate tool_call’s payload field whose value exceeds this many bytes becomes an elision candidate. Default 8192 (mirrors A7/A9’s scale).

§tool_input_elidable_fields: HashMap<String, String>

TR-10 — table of tool name -> its elidable (disk-persisted) payload argument field. Defaults to the built-in write-family tools (write_file -> content, see default_tool_input_elidable_fields); an MCP tool opts in by inserting its own (name, field) entry (SPEC.md TR-10: “per-MCP-tool opt-in”).

§normalize_terminal_output: bool

T30/TR-4 — gate for ReductionKind::OutputNormalized (ANSI/redraw collapse over terminal tool output). Default true: like redact_images, this is a pure function of already-in-view content (no I/O probe needed) and content-lossless (rendered CONTENT is fully preserved, only presentation bytes are removed), so it stacks on by default per D14.

§terminal_output_min_savings: usize

T30/TR-4 — minimum byte savings (original_bytes - normalized_bytes) for a candidate to actually become an ReductionKind::OutputNormalized reduction; below this floor the output is left untouched rather than raced through the reduction machinery for a few bytes (SPEC.md TR-4’s “savings floor” knob). Default normalize::DEFAULT_MIN_SAVINGS.

§duplicate_output_min_bytes: usize

TR-2 — minimum byte length of a duplicate tool-result candidate’s content for it to become a ReductionKind::DuplicateOutput candidate. Below this, both the canonical and the would-be duplicate are left alone: a stub’s own bytes are not free, so deduping a tiny output would spend more than it saves (the “savings floor”). Default 256.

§deduplicate_outputs: bool

TR-2 — gate for ReductionKind::DuplicateOutput. Default true: duplicate detection is a pure function of the recorded tool outputs, so it stacks on in ordinary reduced mode. Composable capability profiles can disable it without changing the savings-floor knob.

§supersede_enabled: bool

TR-6 (T16) — gate for ReductionKind::Superseded (same tool + same canonicalized arguments, keep only the newest result). Default true: like redact_images/elide_tool_inputs, the candidate rule is a pure function of the view plus Self::supersede_command_fields — no external disk probe needed — so it stacks on by default (D14).

§supersede_protect_last_n: usize

TR-6 — protected recency zone (opencode’s PRUNE_PROTECT spirit): the newest N tool RESULT messages (by position, mirrors Self::protect_last_n_tool_results’s own construction) are never a new Superseded candidate, regardless of how many older same-key occurrences exist. A DEDICATED knob rather than reusing protect_last_n_tool_results — TR-6.md’s spec calls this out as its own independently tunable “protected recency zone,” and the two passes run at different points in the pipeline (Superseded runs before A7 truncation ever computes its own candidates). Default 3 (mirrors protect_last_n_tool_results’s own default).

§supersede_min_bytes: usize

TR-6 — minimum byte length of a superseded-candidate’s OWN content for it to become a ReductionKind::Superseded candidate (the “savings floor,” mirrors Self::duplicate_output_min_bytes). Below this the older result is left untouched — a stub’s own bytes are not free. Default 256.

§supersede_command_fields: HashMap<String, String>

TR-6 — table of tool name -> its command-bearing argument field (e.g. bash/shell/exec_command -> "command"), consulted by supersede::canonical_key to canonicalize (trim + collapse internal whitespace) just that one field’s value rather than the whole arguments string. A tool absent from this table still participates in supersession — its whole (trimmed-only) arguments string becomes the key — this table only controls whitespace-collapse scope, not eligibility. Defaults to supersede::default_command_fields.

§prune_errored_inputs: bool

TR-6 — gate for errored-call input pruning: a FAILED tool call’s oversized payload argument (Self::tool_input_elidable_fields, shared with TR-10) becomes a ReductionKind::ToolInputElided candidate once Self::errored_input_prune_after_turns assistant turns have elapsed since the failed call — the disjoint, FAILURE-side complement of TR-10’s elide_tool_inputs (which only ever considers SUCCESSFUL calls; see detect_tool_inputs’s own doc comment for the success/failure boundary). The failed call’s own error-result message is never touched by this — only the assistant-side input argument — so the error itself stays visible exactly as TR-6.md requires. Default true (pure function of the view + the age clock, no I/O probe needed, D14).

§errored_input_prune_after_turns: usize

TR-6 — how many LATER Role::Assistant messages must appear after a failed call’s own message before its oversized input becomes a pruning candidate (the “N turns” aging clock in TR-6.md’s errored-call case) — a message-count proxy for “turns elapsed,” the same convention Self::clear_turns_older_than (A10) already uses (this codebase has no other structural definition of a conversational turn). Default 3.

§summarize_cleared_turns: bool

TR-7 (T20) — the summaries: on|off config knob: gate for rendering an established ReductionKind::TurnsCleared span’s placeholder as an LLM-generated summary paragraph instead of the deterministic [turns cleared] stub. Default false — SPEC.md TR-7 dev/01: with this off, the A10 stub must stay byte-identical to pre-TR-7 behavior, so project_messages never even looks at Self::cleared_turns_summary while this is unset, regardless of what a caller precomputed. Turning this on with no matching Self::cleared_turns_summary entry (e.g. the side-call was never run, or failed) is exactly as safe: the deterministic stub is still what gets rendered (dev/03’s failure-fallback guarantee).

§expected_summary_bytes: usize

TR-7 — cost-guard floor (dev/05): a candidate cleared span’s ORIGINAL byte size (the same range_bytes the deterministic stub’s own summary clause already reports) must exceed expected_summary_bytes * summary_cost_floor_multiple before prepare_cleared_turns_summary ever calls the injected summarize::SpanSummarizer — below the floor, a summarization side-call would be negative-ROI (the stub it replaces is already small) and is skipped outright, never attempted. Default 400 (a rough paragraph-sized estimate).

§summary_cost_floor_multiple: usize

TR-7 — see Self::expected_summary_bytes; the floor multiplier. Default 4 (the span must be at least ~4 summaries’ worth of bytes).

§cleared_turns_summary: Option<PreparedClearSummary>

TR-7 — the side-call preparer’s output (prepare_cleared_turns_summary), consulted by project_messages only when Self::summarize_cleared_turns is set AND the prepared entry’s (first, last) matches EXACTLY the range project_messages independently (re)computes for this call — any other prepared entry (stale, wrong range, or simply absent) is silently ignored and the deterministic stub is rendered instead. This is data, not a config knob (mirrors Self::read_freshness): recomputed by the caller (via prepare_cleared_turns_summary, the one place TR-7’s side-call happens) before every project/project_messages call that might establish a NEW TurnsCleared range. Default: None.

Trait Implementations§

Source§

impl Clone for ReductionPolicy

Source§

fn clone(&self) -> ReductionPolicy

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ReductionPolicy

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ReductionPolicy

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Eq for ReductionPolicy

Source§

impl PartialEq for ReductionPolicy

Source§

fn eq(&self, other: &ReductionPolicy) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ReductionPolicy

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more