use crate::model::{ContextBudget, ContextItem};
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CountRequirementShortfall {
pub kind: String,
pub required_count: usize,
pub satisfied_count: usize,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum PipelineStage {
Classify,
Score,
Deduplicate,
Slice,
Place,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TraceEvent {
pub stage: PipelineStage,
pub duration_ms: f64,
pub item_count: usize,
pub message: Option<String>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct OverflowEvent {
pub tokens_over_budget: i64,
pub overflowing_items: Vec<ContextItem>,
pub budget: ContextBudget,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "reason"))]
pub enum ExclusionReason {
BudgetExceeded {
item_tokens: i64,
available_tokens: i64,
},
ScoredTooLow {
score: f64,
threshold: f64,
},
Deduplicated {
deduplicated_against: String,
},
QuotaCapExceeded {
kind: String,
cap: i64,
actual: i64,
},
QuotaRequireDisplaced {
displaced_by_kind: String,
},
NegativeTokens {
tokens: i64,
},
PinnedOverride {
displaced_by: String,
},
Filtered {
filter_name: String,
},
CountCapExceeded {
kind: String,
cap: usize,
count: usize,
},
CountRequireCandidatesExhausted {
kind: String,
},
#[doc(hidden)]
#[cfg_attr(feature = "serde", serde(other))]
_Unknown,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "reason"))]
pub enum InclusionReason {
Scored,
Pinned,
ZeroToken,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IncludedItem {
pub item: ContextItem,
pub score: f64,
pub reason: InclusionReason,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ExcludedItem {
pub item: ContextItem,
pub score: f64,
pub reason: ExclusionReason,
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct StageTraceSnapshot {
pub stage: PipelineStage,
pub item_count_in: usize,
pub item_count_out: usize,
pub duration_ms: f64,
pub excluded: Vec<ExcludedItem>,
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct SelectionReport {
pub events: Vec<TraceEvent>,
pub included: Vec<IncludedItem>,
pub excluded: Vec<ExcludedItem>,
pub total_candidates: usize,
pub total_tokens_considered: i64,
#[cfg_attr(feature = "serde", serde(default))]
pub count_requirement_shortfalls: Vec<CountRequirementShortfall>,
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for SelectionReport {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
use serde::Deserialize;
#[derive(Deserialize)]
struct RawSelectionReport {
events: Vec<TraceEvent>,
included: Vec<IncludedItem>,
excluded: Vec<ExcludedItem>,
total_candidates: usize,
total_tokens_considered: i64,
#[serde(default)]
count_requirement_shortfalls: Vec<CountRequirementShortfall>,
}
let raw = RawSelectionReport::deserialize(deserializer)?;
let expected = raw.included.len() + raw.excluded.len();
if raw.total_candidates != expected {
return Err(serde::de::Error::custom(format!(
"total_candidates {} does not equal included.len() {} + excluded.len() {}",
raw.total_candidates,
raw.included.len(),
raw.excluded.len(),
)));
}
Ok(SelectionReport {
events: raw.events,
included: raw.included,
excluded: raw.excluded,
total_candidates: raw.total_candidates,
total_tokens_considered: raw.total_tokens_considered,
count_requirement_shortfalls: raw.count_requirement_shortfalls,
})
}
}
pub mod trace_collector;
pub use trace_collector::{
DiagnosticTraceCollector, NullTraceCollector, TraceCollector, TraceDetailLevel,
};