engram/context/
metrics.rs1use serde::{Deserialize, Serialize};
8use serde_json::{json, Value};
9
10const CHARS_PER_TOKEN_ESTIMATE: usize = 4;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct TokenEstimateMetadata {
14 pub tokens_est: i64,
15 pub bytes: usize,
16 pub method: String,
17}
18
19#[derive(Debug, Clone, Default, Serialize, Deserialize)]
20pub struct ContextBundleMetrics {
21 pub metric_type: String,
22 pub estimated: bool,
23 pub method: String,
24 pub retrieved_item_count: usize,
25 pub included_section_entry_count: usize,
26 pub excluded_item_count: usize,
27 pub artifact_pointer_count: usize,
28 pub summarized_artifact_ref_count: usize,
29 pub raw_artifact_ref_count: usize,
30 pub raw_artifact_return_count: usize,
31 pub retrieved_context_tokens_est: i64,
32 pub bundle_tokens_est: i64,
33 pub excluded_tokens_est: Option<i64>,
34 pub notes: Vec<String>,
35}
36
37#[derive(Debug, Clone, Default, Serialize, Deserialize)]
38pub struct ArtifactRetrievalCounters {
39 pub summarized_artifact_refs: usize,
40 pub raw_artifact_refs: usize,
41 pub raw_artifacts_returned: usize,
42}
43
44pub fn estimate_tokens(text: &str) -> i64 {
45 if text.is_empty() {
46 return 0;
47 }
48 text.len().div_ceil(CHARS_PER_TOKEN_ESTIMATE) as i64
49}
50
51pub fn estimate_json_tokens(value: &Value) -> i64 {
52 estimate_tokens(&value.to_string())
53}
54
55pub fn token_estimate_metadata(text: &str) -> TokenEstimateMetadata {
56 TokenEstimateMetadata {
57 tokens_est: estimate_tokens(text),
58 bytes: text.len(),
59 method: "chars_div_4_estimate".to_string(),
60 }
61}
62
63pub fn estimated_savings_tokens(
64 raw_tokens: Option<i64>,
65 compact_tokens: Option<i64>,
66) -> Option<i64> {
67 match (raw_tokens, compact_tokens) {
68 (Some(raw), Some(compact)) if raw >= compact => Some(raw - compact),
69 _ => None,
70 }
71}
72
73pub fn metrics_value(
74 observed_input_tokens_est: Option<i64>,
75 stored_artifact_tokens_est: Option<i64>,
76 summary_tokens_est: Option<i64>,
77) -> Value {
78 json!({
79 "estimated": true,
80 "method": "chars_div_4_estimate_or_caller_supplied",
81 "observed_input_tokens_est": observed_input_tokens_est,
82 "stored_artifact_tokens_est": stored_artifact_tokens_est,
83 "summary_tokens_est": summary_tokens_est,
84 "estimated_savings_tokens": estimated_savings_tokens(
85 observed_input_tokens_est,
86 summary_tokens_est.or(stored_artifact_tokens_est),
87 ),
88 "claim": "cross_session_retrieval_estimate_only"
89 })
90}