Skip to main content

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