pub mod budget;
pub mod filter;
pub mod shape;
#[cfg(test)]
mod tests;
use filter::FilterExpr;
use serde_json::{json, Map, Value};
use std::sync::OnceLock;
#[derive(Debug, Clone, Default)]
pub struct AgentSurface {
pub command: Option<String>,
pub select: Vec<String>,
pub filters: Vec<FilterExpr>,
pub sort: Option<String>,
pub dedupe_by: Option<String>,
pub max_items: usize,
pub count_only: bool,
pub truncate_content: usize,
pub max_output_bytes: usize,
}
impl AgentSurface {
pub fn is_noop(&self) -> bool {
self.select.is_empty()
&& self.filters.is_empty()
&& self.sort.is_none()
&& self.dedupe_by.is_none()
&& self.max_items == 0
&& !self.count_only
&& self.truncate_content == 0
&& self.max_output_bytes == 0
}
}
static SURFACE: OnceLock<AgentSurface> = OnceLock::new();
pub fn init(surface: AgentSurface) {
let _ = SURFACE.set(surface);
}
pub fn get() -> &'static AgentSurface {
static INERT: OnceLock<AgentSurface> = OnceLock::new();
SURFACE
.get()
.unwrap_or_else(|| INERT.get_or_init(AgentSurface::default))
}
pub fn active() -> bool {
!get().is_noop()
}
pub fn apply_global(value: Value) -> Value {
apply(get(), value)
}
const META_KEY: &str = "agent_surface";
const TRUNCATED_KEY: &str = "truncated";
pub fn apply(surface: &AgentSurface, mut value: Value) -> Value {
if surface.is_noop() || is_passthrough(&value) {
return value;
}
let array_key = locate_result_array(&value);
let aliases_removed = suppress_alias_arrays(surface, &mut value, array_key.as_deref());
let items = take_items(&mut value, array_key.as_deref());
let (payload, mut meta) = match items {
Some(items) => shape_items(surface, value, array_key.as_deref(), items),
None => shape_scalar_envelope(surface, value),
};
if !aliases_removed.is_empty() {
meta.insert("aliases_removed".into(), json!(aliases_removed));
}
finalize(surface, payload, array_key.as_deref(), meta)
}
fn suppress_alias_arrays(
surface: &AgentSurface,
value: &mut Value,
array_key: Option<&str>,
) -> Vec<String> {
let Some(canonical) = array_key else {
return Vec::new();
};
let Some(command) = surface.command.as_deref() else {
return Vec::new();
};
let Some((_, _, aliases)) = crate::constants::AGENT_SURFACE_ALIAS_ARRAYS
.iter()
.find(|(cmd, key, _)| *cmd == command && *key == canonical)
else {
return Vec::new();
};
let Some(map) = value.as_object_mut() else {
return Vec::new();
};
let mut removed = Vec::new();
for alias in *aliases {
if map.get(*alias).is_some_and(Value::is_array) {
map.remove(*alias);
removed.push((*alias).to_string());
}
}
removed
}
fn is_passthrough(value: &Value) -> bool {
let Some(map) = value.as_object() else {
return false;
};
if map.contains_key("$schema") {
return true;
}
if map.get("error") == Some(&Value::Bool(true)) {
return true;
}
map.get("ok") == Some(&Value::Bool(false))
}
fn locate_result_array(value: &Value) -> Option<String> {
let map = value.as_object()?;
for candidate in crate::constants::AGENT_SURFACE_RESULT_KEYS {
if map.get(*candidate).is_some_and(Value::is_array) {
return Some((*candidate).to_string());
}
}
map.iter()
.find(|(_, v)| v.is_array())
.map(|(k, _)| k.clone())
}
fn take_items(value: &mut Value, array_key: Option<&str>) -> Option<Vec<Value>> {
match array_key {
Some(key) => match value.as_object_mut()?.get_mut(key)? {
Value::Array(items) => Some(std::mem::take(items)),
_ => None,
},
None => match value {
Value::Array(items) => Some(std::mem::take(items)),
_ => None,
},
}
}
fn shape_items(
surface: &AgentSurface,
mut envelope: Value,
array_key: Option<&str>,
items: Vec<Value>,
) -> (Value, Map<String, Value>) {
let input_count = items.len();
let mut items = shape::filter(items, &surface.filters);
if let Some(key) = &surface.sort {
items = shape::sort(items, key);
}
if let Some(key) = &surface.dedupe_by {
items = shape::dedupe(items, key);
}
items = shape::limit(items, surface.max_items);
items = shape::project(items, &surface.select);
let output_count = items.len();
if surface.count_only {
let mut meta = base_meta(surface, input_count, output_count);
meta.insert("count_only".into(), Value::Bool(true));
return (json!({ "count": output_count }), meta);
}
let secondary_capped = cap_secondary_arrays(&mut envelope, surface.max_items);
match array_key {
Some(key) => {
if let Some(map) = envelope.as_object_mut() {
map.insert(key.to_string(), Value::Array(items));
}
}
None => envelope = Value::Array(items),
}
let mut meta = base_meta(surface, input_count, output_count);
if !secondary_capped.is_empty() {
meta.insert("secondary_capped".into(), json!(secondary_capped));
}
(envelope, meta)
}
fn cap_secondary_arrays(envelope: &mut Value, max_items: usize) -> Vec<String> {
if max_items == 0 {
return Vec::new();
}
let Some(map) = envelope.as_object_mut() else {
return Vec::new();
};
let mut capped = Vec::new();
for (key, value) in map.iter_mut() {
if let Value::Array(items) = value {
if items.len() > max_items {
items.truncate(max_items);
capped.push(key.clone());
}
}
}
capped
}
fn shape_scalar_envelope(surface: &AgentSurface, envelope: Value) -> (Value, Map<String, Value>) {
if surface.count_only {
let mut meta = base_meta(surface, 1, 1);
meta.insert("count_only".into(), Value::Bool(true));
return (json!({ "count": 1 }), meta);
}
let projected = shape::project_one(envelope, &surface.select);
(projected, base_meta(surface, 1, 1))
}
fn base_meta(surface: &AgentSurface, input: usize, output: usize) -> Map<String, Value> {
let mut meta = Map::new();
meta.insert("input_count".into(), json!(input));
meta.insert("output_count".into(), json!(output));
if !surface.select.is_empty() {
meta.insert("select".into(), json!(surface.select));
}
if !surface.filters.is_empty() {
meta.insert("filters".into(), json!(surface.filters.len()));
}
if let Some(key) = &surface.sort {
meta.insert("sort".into(), json!(key));
}
if let Some(key) = &surface.dedupe_by {
meta.insert("dedupe_by".into(), json!(key));
}
if surface.max_items > 0 {
meta.insert("max_items".into(), json!(surface.max_items));
}
meta
}
fn finalize(
surface: &AgentSurface,
mut payload: Value,
array_key: Option<&str>,
mut meta: Map<String, Value>,
) -> Value {
let content_truncated = shape::truncate_strings(&mut payload, surface.truncate_content);
if content_truncated {
meta.insert("content_truncated".into(), Value::Bool(true));
meta.insert("truncate_content".into(), json!(surface.truncate_content));
}
attach_meta(&mut payload, &meta, content_truncated);
let headroom = budget_headroom(surface, &payload, &meta);
let effective_max = match surface.max_output_bytes {
0 => 0,
max => max.saturating_sub(headroom).max(1),
};
let outcome = budget::enforce(&mut payload, array_key, effective_max);
if outcome.truncated && !outcome.stub {
meta.insert("output_truncated".into(), Value::Bool(true));
meta.insert("dropped".into(), json!(outcome.dropped));
meta.insert("max_output_bytes".into(), json!(surface.max_output_bytes));
if let Some(surviving) = surviving_len(&payload, array_key) {
meta.insert("output_count".into(), json!(surviving));
}
attach_meta(&mut payload, &meta, true);
}
if outcome.stub {
if let Some(map) = payload.as_object_mut() {
map.insert("max_output_bytes".into(), json!(surface.max_output_bytes));
}
}
payload
}
fn surviving_len(payload: &Value, array_key: Option<&str>) -> Option<usize> {
match array_key {
Some(key) => payload.get(key)?.as_array().map(Vec::len),
None => payload.as_array().map(Vec::len),
}
}
fn budget_headroom(surface: &AgentSurface, payload: &Value, meta: &Map<String, Value>) -> usize {
if surface.max_output_bytes == 0 {
return 0;
}
let widest_dropped = meta
.get("input_count")
.and_then(Value::as_u64)
.unwrap_or_default();
let mut annotated = meta.clone();
annotated.insert("output_truncated".into(), Value::Bool(true));
annotated.insert("dropped".into(), json!(widest_dropped));
annotated.insert("max_output_bytes".into(), json!(surface.max_output_bytes));
let before = encoded_len(&Value::Object(meta.clone()));
let after = encoded_len(&Value::Object(annotated));
let mut extra = after.saturating_sub(before);
if payload
.as_object()
.is_some_and(|map| !map.contains_key(TRUNCATED_KEY))
{
extra += TRUNCATED_KEY.len() + r#","":true"#.len();
}
extra
}
fn encoded_len(value: &Value) -> usize {
serde_json::to_string(value).map_or(0, |s| s.len())
}
fn attach_meta(payload: &mut Value, meta: &Map<String, Value>, truncated: bool) {
let Some(map) = payload.as_object_mut() else {
return;
};
map.insert(META_KEY.to_string(), Value::Object(meta.clone()));
if truncated && !map.contains_key(TRUNCATED_KEY) {
map.insert(TRUNCATED_KEY.to_string(), Value::Bool(true));
}
}