zeph_context/input.rs
1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Input types for context assembly.
5//!
6//! [`ContextAssemblyInput`] collects all references needed for one assembly turn.
7//! [`ContextMemoryView`] is a snapshot of memory-subsystem configuration that the
8//! assembler reads but never mutates — callers in `zeph-core` populate it from
9//! `MemoryState` before each assembly pass.
10
11use std::borrow::Cow;
12use std::sync::Arc;
13
14use zeph_common::PlannedToolHint;
15use zeph_common::memory::{CompressionLevel, ContextMemoryBackend, FunctionalType};
16use zeph_config::{
17 DocumentConfig, GraphConfig, PersonaConfig, ReasoningConfig, TrajectoryConfig, TreeConfig,
18};
19
20use crate::manager::ContextManager;
21
22/// All borrowed data needed to assemble context for one agent turn.
23///
24/// All fields are shared references — `ContextAssembler::gather` never mutates any state.
25/// The caller (in `zeph-core`) is responsible for populating this struct and passing it to
26/// [`crate::assembler::ContextAssembler::gather`].
27pub struct ContextAssemblyInput<'a> {
28 /// Snapshot of memory subsystem configuration for this turn.
29 pub memory: &'a ContextMemoryView,
30 /// Context lifecycle state machine.
31 pub context_manager: &'a ContextManager,
32 /// Token counter for budget enforcement.
33 pub token_counter: &'a dyn zeph_common::memory::TokenCounting,
34 /// Text of the skills prompt injected in the last turn (used for budget calculation).
35 pub skills_prompt: &'a str,
36 /// Index RAG accessor. `None` when code-index is disabled.
37 pub index: Option<&'a dyn IndexAccess>,
38 /// Learning engine corrections config. `None` when self-learning is disabled.
39 pub correction_config: Option<CorrectionConfig>,
40 /// Current value of the sidequest turn counter, for adaptive strategy selection.
41 pub sidequest_turn_counter: u64,
42 /// Message window snapshot used for strategy resolution and system-prompt extraction.
43 pub messages: &'a [zeph_llm::provider::Message],
44 /// The user query for the current turn, used as the search query for all memory lookups.
45 pub query: &'a str,
46 /// Content scrubber for PII removal. Passed as a function pointer to avoid a dependency
47 /// on `zeph-core`'s redact module.
48 pub scrub: fn(&str) -> Cow<'_, str>,
49 /// Compression tiers active for this turn, derived from the retrieval policy.
50 ///
51 /// The assembler skips fetchers whose tier is not present in this slice.
52 /// An empty slice means "no tier filtering" — all fetchers run subject to their own budget
53 /// gates. This is the defensive default: a caller that accidentally passes an empty slice
54 /// will get the same behaviour as before this field existed, rather than silently dropping
55 /// all memory recall.
56 ///
57 /// A caller computing this from a config-driven policy must guarantee non-empty intent or
58 /// accept that an empty slice disables tier-based filtering entirely.
59 pub active_levels: &'a [CompressionLevel],
60 /// Active functional memory types for this turn's type-aware retrieval composition
61 /// (spec 004-16, #6086), resolved by `zeph-agent-context` from `TypeAwareComposeConfig`.
62 ///
63 /// An empty slice means "no type gating" — every gated fetcher runs subject to its
64 /// existing activity/budget guard, identical to pre-#6086 behaviour. This is both the
65 /// `enabled = false` no-op case and the `default_compose_types = []` ("all types") case;
66 /// resolving both to an empty slice keeps `schedule_context_fetchers`'s gate a single
67 /// `active.is_empty() || active.contains(&type)` check.
68 pub active_types: &'a [FunctionalType],
69 /// Pre-built memory router for this turn. Built by `zeph-core` via `build_memory_router()`
70 /// and passed in to avoid a `zeph-memory` dependency inside `zeph-context`.
71 pub router: Box<dyn zeph_common::memory::AsyncMemoryRouter + Send + Sync>,
72 /// Lookahead hints from the orchestration DAG for plan-aware scoring.
73 ///
74 /// Pass `&[]` when no DAG context is available (PAACE data structure only in MVP).
75 pub planned_next_tools: &'a [PlannedToolHint],
76}
77
78/// Configuration extracted from `LearningEngine` needed by correction recall.
79///
80/// Populated from `LearningEngine::config` in `zeph-core` and passed into
81/// [`ContextAssemblyInput`].
82#[derive(Debug, Clone, Copy)]
83pub struct CorrectionConfig {
84 /// Whether correction detection is active.
85 pub correction_detection: bool,
86 /// Maximum number of corrections to recall per turn.
87 pub correction_recall_limit: u32,
88 /// Minimum similarity score for a correction to be considered relevant.
89 pub correction_min_similarity: f32,
90}
91
92/// Read-only snapshot of memory subsystem state needed for context assembly.
93///
94/// This struct is populated by the caller (`zeph-core`) from `MemoryState` before each
95/// assembly pass. It contains only the fields that [`crate::assembler::ContextAssembler`]
96/// actually reads — no `Agent` methods, no mutation.
97pub struct ContextMemoryView {
98 // ── persistence fields ────────────────────────────────────────────────────
99 /// Semantic memory backend. `None` when memory is disabled.
100 pub memory: Option<Arc<dyn ContextMemoryBackend>>,
101 /// Active conversation ID (`conversations.id` raw value). `None` before the first message is persisted.
102 pub conversation_id: Option<i64>,
103 /// Maximum number of semantic recall hits injected per turn.
104 pub recall_limit: usize,
105 /// Minimum semantic similarity score for cross-session recall (0.0–1.0).
106 pub cross_session_score_threshold: f32,
107
108 // ── compaction fields ─────────────────────────────────────────────────────
109 /// Context assembly strategy (`FullHistory` / `MemoryFirst` / `Adaptive`).
110 pub context_strategy: zeph_config::ContextStrategy,
111 /// Turn threshold for `Adaptive` strategy crossover.
112 pub crossover_turn_threshold: u32,
113 /// Cached session digest text and token count, loaded at session start.
114 pub cached_session_digest: Option<(String, usize)>,
115
116 // ── extraction fields ─────────────────────────────────────────────────────
117 /// Knowledge graph configuration.
118 pub graph_config: GraphConfig,
119 /// Document RAG configuration.
120 pub document_config: DocumentConfig,
121 /// Persona memory configuration.
122 pub persona_config: PersonaConfig,
123 /// Trajectory-informed memory configuration.
124 pub trajectory_config: TrajectoryConfig,
125 /// `ReasoningBank` configuration (#3343).
126 pub reasoning_config: ReasoningConfig,
127 /// `MemCoT` semantic state configuration (#3574).
128 pub memcot_config: zeph_config::MemCotConfig,
129 /// Current `MemCoT` semantic state buffer snapshot. `Some` when `MemCoT` is enabled and the
130 /// accumulator has distilled at least one turn.
131 pub memcot_state: Option<String>,
132
133 // ── subsystem fields ──────────────────────────────────────────────────────
134 /// `TiMem` temporal-hierarchical memory tree configuration.
135 pub tree_config: TreeConfig,
136}
137
138/// Read-only access to a code-index retriever.
139///
140/// Implemented by `IndexState` in `zeph-core`. The assembler calls only `fetch_code_rag`
141/// to populate the `code_context` slot.
142///
143/// The return type uses `Pin<Box<dyn Future>>` rather than `async fn` to preserve
144/// dyn-compatibility: the trait is used as `&dyn IndexAccess` in `ContextAssemblyInput`.
145pub trait IndexAccess: Send + Sync {
146 /// Retrieve up to `budget_tokens` of code context for the given `query`.
147 ///
148 /// Returns `None` when no relevant context is found or when code-index is disabled.
149 ///
150 /// # Errors
151 ///
152 /// Propagates errors from the underlying code retriever.
153 fn fetch_code_rag<'a>(
154 &'a self,
155 query: &'a str,
156 budget_tokens: usize,
157 ) -> std::pin::Pin<
158 Box<
159 dyn std::future::Future<Output = Result<Option<String>, crate::error::AssemblerError>>
160 + Send
161 + 'a,
162 >,
163 >;
164}