mod findings;
mod hash;
mod measured;
mod normalize;
mod record;
mod report;
mod table;
#[cfg(feature = "net")]
pub mod proxy;
#[cfg(feature = "net")]
pub mod tokenize;
use serde::{Deserialize, Serialize};
pub use findings::{Confidence, Finding, FindingKind};
pub use measured::{Measured, Source};
pub use normalize::{Api, Counts};
pub use record::{
BadLine, ExchangeError, MessageDigest, Output, Params, ReadResult, Record, RequestDigest,
RequestRecord, ResponseDigest, ResponseRecord, StreamKind, TokenCounts, ToolCall, ToolDigest,
read_jsonl, write_jsonl,
};
pub use report::{
CauseTotal, CompositionTotals, CountField, Coverage, Report, ServerFields, SkippedCounts, Time,
Window,
};
pub use table::{BreakCause, Cause, Client, Composition, Loss, Row, RowKind, Shape, ToolUsage};
pub const RECORD_VERSION: u32 = 1;
pub const REPORT_VERSION: u32 = 1;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Config {
pub session_gap_ms: u64,
pub thresholds: Thresholds,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Thresholds {
pub tool_schema_tokens: u32,
pub system_tokens: u32,
}
impl Default for Config {
fn default() -> Self {
Config {
session_gap_ms: 60_000,
thresholds: Thresholds::default(),
}
}
}
impl Default for Thresholds {
fn default() -> Self {
Thresholds {
tool_schema_tokens: 800,
system_tokens: 800,
}
}
}
pub fn analyze(records: &[Record], config: &Config) -> Report {
let normalized = normalize::normalize_all(records);
let table = table::build(&normalized.exchanges, config);
let findings = findings::find(&table, config);
report::assemble(records, &normalized, table, findings)
}