use std::collections::BTreeMap;
use std::io::{self, Write};
use serde::Serialize;
use serde_json::Value;
use crate::models::Tool;
const MAX_RENDERED_TOOLS: usize = 32;
const MAX_NAME_CHARS: usize = 256;
const MAX_DESCRIPTION_CHARS: usize = 512;
const MAX_SCHEMA_BYTES: usize = 2_048;
const MAX_AUXILIARY_CHARS: usize = 512;
const MAX_ALLOWED_CALLERS: usize = 16;
const MAX_ALLOWED_CALLER_CHARS: usize = 128;
const MAX_PAYLOAD_MEASUREMENT_BYTES: usize = 1_048_576;
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BoundedString {
pub value: String,
pub truncated: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum Evidence<T> {
Known { value: T },
Unknown { reason: String },
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct BoundedList {
pub count: usize,
pub rendered: Vec<BoundedString>,
pub omitted: usize,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct CountOnly {
pub count: usize,
pub values: &'static str,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct RegistryFacts {
pub name: String,
pub description: String,
pub model_visible: bool,
pub capabilities: Vec<String>,
pub approval: String,
pub plugin: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolProvenance {
Builtin,
Plugin,
Mcp,
Synthetic,
Unknown,
}
impl ToolProvenance {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Builtin => "builtin",
Self::Plugin => "plugin",
Self::Mcp => "mcp",
Self::Synthetic => "synthetic",
Self::Unknown => "unknown",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ToolVisibility {
Active,
Deferred,
InRequest,
RegistryOnly,
Hidden,
}
impl ToolVisibility {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Active => "active",
Self::Deferred => "deferred",
Self::InRequest => "in-request",
Self::RegistryOnly => "registry-only",
Self::Hidden => "hidden",
}
}
#[must_use]
pub const fn in_request(self) -> bool {
matches!(self, Self::Active | Self::Deferred | Self::InRequest)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
#[serde(tag = "status", rename_all = "snake_case")]
pub enum ProviderAvailability {
#[default]
Unknown,
Available { provider: String, model: String },
Unavailable { reason: String },
}
impl ProviderAvailability {
#[must_use]
pub const fn is_available(&self) -> bool {
matches!(self, Self::Available { .. })
}
#[must_use]
pub const fn label(&self) -> &'static str {
match self {
Self::Unknown => "unknown",
Self::Available { .. } => "available",
Self::Unavailable { .. } => "unavailable",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct ToolSurfaceContext {
pub registry: Vec<RegistryFacts>,
pub mcp_servers: BTreeMap<String, String>,
pub synthetic_names: Vec<String>,
pub provider: ProviderAvailability,
}
impl ToolSurfaceContext {
fn provenance(&self, name: &str) -> ToolProvenance {
if let Some(facts) = self.registry.iter().find(|facts| facts.name == name) {
if facts.plugin {
return ToolProvenance::Plugin;
}
if self.mcp_servers.contains_key(name) {
return ToolProvenance::Mcp;
}
return ToolProvenance::Builtin;
}
if self.mcp_servers.contains_key(name) {
return ToolProvenance::Mcp;
}
if self.synthetic_names.iter().any(|entry| entry == name) {
return ToolProvenance::Synthetic;
}
ToolProvenance::Unknown
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ToolProjection {
pub ordinal: usize,
pub name: BoundedString,
pub tool_type: Evidence<BoundedString>,
pub description: BoundedString,
pub input_schema_json: BoundedString,
pub allowed_callers: Evidence<BoundedList>,
pub defer_loading: Evidence<bool>,
pub input_examples: Evidence<CountOnly>,
pub strict: Evidence<bool>,
pub cache_control_type: Evidence<BoundedString>,
pub provenance: Evidence<ToolProvenance>,
pub mcp_server: Evidence<BoundedString>,
pub capabilities: Evidence<BoundedList>,
pub approval: Evidence<BoundedString>,
pub model_visible: Evidence<bool>,
pub visibility: ToolVisibility,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ToolInspectionSnapshot {
pub schema_version: u32,
pub capture_source: &'static str,
pub delivery_status: &'static str,
pub turn_id: BoundedString,
pub step: u32,
pub tools_field_present: bool,
pub tool_count: usize,
pub rendered_tool_count: usize,
pub omitted_tool_count: usize,
pub payload_json_bytes: Option<usize>,
pub payload_measurement_status: String,
pub active_tool_catalog_sha256: Option<String>,
pub unavailable_for_this_request: Vec<&'static str>,
pub provider: ProviderAvailability,
pub registry_facts_present: bool,
pub registry_tool_count: Evidence<usize>,
pub registry_only_tools: Evidence<BoundedList>,
pub tools: Vec<ToolProjection>,
}
impl ToolInspectionSnapshot {
#[must_use]
pub fn from_prepared_request(turn_id: &str, step: u32, tools: Option<&[Tool]>) -> Self {
Self::from_prepared_request_with_surface(turn_id, step, tools, None)
}
#[must_use]
pub fn from_prepared_request_with_surface(
turn_id: &str,
step: u32,
tools: Option<&[Tool]>,
surface: Option<&ToolSurfaceContext>,
) -> Self {
let tool_count = tools.map_or(0, <[Tool]>::len);
let projected = tools
.unwrap_or_default()
.iter()
.take(MAX_RENDERED_TOOLS)
.enumerate()
.map(|(index, tool)| project_tool(index, tool, surface))
.collect::<Vec<_>>();
let (payload_json_bytes, payload_measurement_status) = measure_payload(tools);
let request_names = tools
.unwrap_or_default()
.iter()
.map(|tool| tool.name.as_str())
.collect::<std::collections::BTreeSet<_>>();
let registry_only_tools = surface.map_or_else(
|| unknown("registry facts not captured for this request"),
|surface| {
let names = surface
.registry
.iter()
.filter(|facts| {
facts.model_visible && !request_names.contains(facts.name.as_str())
})
.map(|facts| facts.name.as_str())
.collect::<Vec<_>>();
let rendered = names
.iter()
.take(MAX_RENDERED_TOOLS)
.map(|name| bounded_chars(name, MAX_NAME_CHARS))
.collect::<Vec<_>>();
Evidence::Known {
value: BoundedList {
count: names.len(),
omitted: names.len().saturating_sub(rendered.len()),
rendered,
},
}
},
);
let mut unavailable_for_this_request = vec!["provider_wire_payload"];
if surface.is_none() {
unavailable_for_this_request.extend([
"provider",
"model",
"approval",
"provenance",
"capabilities",
]);
} else if !surface.is_some_and(|surface| surface.provider.is_available()) {
unavailable_for_this_request.extend(["provider", "model"]);
}
Self {
schema_version: 1,
capture_source: "prepared model-client request",
delivery_status: "unknown (capture does not prove provider delivery)",
turn_id: bounded_chars(turn_id, MAX_AUXILIARY_CHARS),
step,
tools_field_present: tools.is_some(),
tool_count,
rendered_tool_count: projected.len(),
omitted_tool_count: tool_count.saturating_sub(projected.len()),
payload_json_bytes,
payload_measurement_status,
active_tool_catalog_sha256: tools
.map(crate::core::engine::preview::active_tool_catalog_sha256),
unavailable_for_this_request,
provider: surface.map_or(ProviderAvailability::Unknown, |surface| {
surface.provider.clone()
}),
registry_facts_present: surface.is_some(),
registry_tool_count: surface.map_or_else(
|| unknown("registry facts not captured for this request"),
|surface| Evidence::Known {
value: surface.registry.len(),
},
),
registry_only_tools,
tools: projected,
}
}
#[must_use]
pub fn render_text(&self) -> String {
let mut out = String::new();
out.push_str("Prepared Model-Client Tool Request (read-only)\n");
out.push_str(&format!("Capture source: {}\n", self.capture_source));
out.push_str(&format!("Delivery: {}\n", self.delivery_status));
out.push_str(&format!(
"Turn: {}\nTurn truncated: {}\n",
json_string(&self.turn_id.value),
yes_no(self.turn_id.truncated)
));
out.push_str(&format!("Step: {}\n", self.step));
out.push_str(&format!(
"Tools field: {}\nTool count: {}\n",
if self.tools_field_present {
"present"
} else {
"absent"
},
self.tool_count
));
out.push_str(&format!(
"Rendered tools: {}; omitted by render bound: {}\n",
self.rendered_tool_count, self.omitted_tool_count
));
out.push_str(&format!(
"Model-client payload measurement: {}\n",
self.payload_measurement_status
));
out.push_str(&format_optional_usize(
"Model-client tool JSON bytes",
self.payload_json_bytes,
));
out.push_str(&format_optional_string(
"Active tool catalog digest (same digest as the request manifest)",
self.active_tool_catalog_sha256.as_deref(),
));
out.push_str(
"Provider-wire tool payload: unavailable (the provider adapter may transform or omit model-client fields)\n",
);
match &self.provider {
ProviderAvailability::Available { provider, model } => out.push_str(&format!(
"Provider: {} (resolved model client)\nModel: {}\n",
json_string(provider),
json_string(model)
)),
ProviderAvailability::Unavailable { reason } => {
out.push_str(&format!("Provider: unavailable ({reason})\n"));
}
ProviderAvailability::Unknown => {
out.push_str("Provider: unknown (no model-client receipt captured)\n");
}
}
out.push_str(&format!(
"Registry facts: {}\n",
if self.registry_facts_present {
"captured"
} else {
"not captured"
}
));
match &self.registry_tool_count {
Evidence::Known { value } => {
out.push_str(&format!("Registered tools: {value}\n"));
}
Evidence::Unknown { reason } => {
out.push_str(&format!("Registered tools: unknown ({reason})\n"));
}
}
match &self.registry_only_tools {
Evidence::Known { value } => {
let rendered = value
.rendered
.iter()
.map(|entry| entry.value.as_str())
.collect::<Vec<_>>();
out.push_str(&format!(
"Model-visible tools not in this request: {}\n names: {}\n omitted by render bound: {}\n",
value.count,
serde_json::to_string(&rendered).unwrap_or_else(|_| "unavailable".to_string()),
value.omitted
));
}
Evidence::Unknown { reason } => {
out.push_str(&format!(
"Model-visible tools not in this request: unknown ({reason})\n"
));
}
}
out.push_str(&format!(
"Unavailable for this request: {}\n",
self.unavailable_for_this_request.join(", ")
));
for tool in &self.tools {
out.push_str(&format!(
"\n{}. {}\n",
tool.ordinal,
json_string(&tool.name.value)
));
out.push_str(&format!(
" name truncated: {}\n",
yes_no(tool.name.truncated)
));
render_bounded_evidence(&mut out, "type", &tool.tool_type);
out.push_str(&format!(
" description: {}\n description truncated: {}\n",
json_string(&tool.description.value),
yes_no(tool.description.truncated)
));
out.push_str(&format!(
" input schema JSON: {}\n input schema truncated: {}\n",
tool.input_schema_json.value,
yes_no(tool.input_schema_json.truncated)
));
match &tool.allowed_callers {
Evidence::Known { value } => {
let rendered = value
.rendered
.iter()
.map(|entry| entry.value.as_str())
.collect::<Vec<_>>();
out.push_str(&format!(
" allowed callers: {}\n allowed callers count: {}\n allowed callers omitted: {}\n allowed callers truncated: {}\n",
serde_json::to_string(&rendered).unwrap_or_else(|_| "unavailable".to_string()),
value.count,
value.omitted,
yes_no(value.rendered.iter().any(|entry| entry.truncated))
));
}
Evidence::Unknown { reason } => {
out.push_str(&format!(" allowed callers: unknown ({reason})\n"));
}
}
render_bool_evidence(&mut out, "deferred loading", &tool.defer_loading);
render_bool_evidence(&mut out, "strict", &tool.strict);
match &tool.input_examples {
Evidence::Known { value } => out.push_str(&format!(
" input examples: present ({} value(s), {})\n",
value.count, value.values
)),
Evidence::Unknown { reason } => {
out.push_str(&format!(" input examples: unknown ({reason})\n"));
}
}
render_bounded_evidence(&mut out, "cache control type", &tool.cache_control_type);
out.push_str(&format!(
" request state: {}\n in request: {}\n",
tool.visibility.label(),
yes_no(tool.visibility.in_request())
));
match &tool.provenance {
Evidence::Known { value } => {
out.push_str(&format!(" provenance: {}\n", value.label()));
}
Evidence::Unknown { reason } => {
out.push_str(&format!(" provenance: unknown ({reason})\n"));
}
}
render_bounded_evidence(&mut out, "MCP server", &tool.mcp_server);
match &tool.capabilities {
Evidence::Known { value } => {
let rendered = value
.rendered
.iter()
.map(|entry| entry.value.as_str())
.collect::<Vec<_>>();
out.push_str(&format!(
" capabilities: {}\n capabilities count: {}\n capabilities omitted: {}\n",
serde_json::to_string(&rendered)
.unwrap_or_else(|_| "unavailable".to_string()),
value.count,
value.omitted
));
}
Evidence::Unknown { reason } => {
out.push_str(&format!(" capabilities: unknown ({reason})\n"));
}
}
render_bounded_evidence(&mut out, "approval", &tool.approval);
render_bool_evidence(&mut out, "model visible", &tool.model_visible);
}
out
}
pub fn render_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(self)
}
}
fn project_tool(index: usize, tool: &Tool, surface: Option<&ToolSurfaceContext>) -> ToolProjection {
let facts = surface.and_then(|surface| {
surface
.registry
.iter()
.find(|facts| facts.name == tool.name)
});
let no_surface = "surface context not captured for this request";
let not_registered = "tool is not in the registry";
ToolProjection {
ordinal: index + 1,
name: bounded_chars(&tool.name, MAX_NAME_CHARS),
tool_type: optional_bounded(tool.tool_type.as_deref()),
description: bounded_chars(&tool.description, MAX_DESCRIPTION_CHARS),
input_schema_json: bounded_json(&tool.input_schema, MAX_SCHEMA_BYTES),
allowed_callers: tool.allowed_callers.as_ref().map_or_else(
|| unknown("request field absent"),
|values| {
let rendered = values
.iter()
.take(MAX_ALLOWED_CALLERS)
.map(|value| bounded_chars(value, MAX_ALLOWED_CALLER_CHARS))
.collect::<Vec<_>>();
Evidence::Known {
value: BoundedList {
count: values.len(),
omitted: values.len().saturating_sub(rendered.len()),
rendered,
},
}
},
),
defer_loading: optional_copy(tool.defer_loading.as_ref()),
input_examples: tool.input_examples.as_ref().map_or_else(
|| unknown("request field absent"),
|values| Evidence::Known {
value: CountOnly {
count: values.len(),
values: "values omitted from bounded projection",
},
},
),
strict: optional_copy(tool.strict.as_ref()),
cache_control_type: optional_bounded(
tool.cache_control
.as_ref()
.map(|value| value.cache_type.as_str()),
),
provenance: surface.map_or_else(
|| unknown(no_surface),
|surface| Evidence::Known {
value: surface.provenance(&tool.name),
},
),
mcp_server: surface.map_or_else(
|| unknown(no_surface),
|surface| {
surface.mcp_servers.get(&tool.name).map_or_else(
|| unknown("the MCP pool did not attribute this tool name"),
|server| Evidence::Known {
value: bounded_chars(server, MAX_AUXILIARY_CHARS),
},
)
},
),
capabilities: match (surface, facts) {
(None, _) => unknown(no_surface),
(Some(_), None) => unknown(not_registered),
(Some(_), Some(facts)) => {
let rendered = facts
.capabilities
.iter()
.take(MAX_ALLOWED_CALLERS)
.map(|value| bounded_chars(value, MAX_ALLOWED_CALLER_CHARS))
.collect::<Vec<_>>();
Evidence::Known {
value: BoundedList {
count: facts.capabilities.len(),
omitted: facts.capabilities.len().saturating_sub(rendered.len()),
rendered,
},
}
}
},
approval: match (surface, facts) {
(None, _) => unknown(no_surface),
(Some(_), None) => unknown(not_registered),
(Some(_), Some(facts)) => Evidence::Known {
value: bounded_chars(&facts.approval, MAX_AUXILIARY_CHARS),
},
},
model_visible: match (surface, facts) {
(None, _) => unknown(no_surface),
(Some(_), None) => unknown(not_registered),
(Some(_), Some(facts)) => Evidence::Known {
value: facts.model_visible,
},
},
visibility: match tool.defer_loading {
Some(true) => ToolVisibility::Deferred,
Some(false) => ToolVisibility::Active,
None => ToolVisibility::InRequest,
},
}
}
fn measure_payload(tools: Option<&[Tool]>) -> (Option<usize>, String) {
let Some(tools) = tools else {
return (None, "unavailable (tools field absent)".to_string());
};
let mut writer = BoundedWriter::new(MAX_PAYLOAD_MEASUREMENT_BYTES);
match serde_json::to_writer(&mut writer, tools) {
Ok(()) => (
Some(writer.bytes.len()),
"exact (within 1048576-byte measurement bound)".to_string(),
),
Err(_) if writer.exceeded => (
None,
"unavailable (payload exceeds 1048576-byte measurement bound)".to_string(),
),
Err(_) => (None, "unavailable (serialization failed)".to_string()),
}
}
fn bounded_json(value: &Value, limit: usize) -> BoundedString {
let mut writer = BoundedWriter::new(limit);
let result = serde_json::to_writer(&mut writer, value);
BoundedString {
value: String::from_utf8_lossy(&writer.bytes).into_owned(),
truncated: result.is_err() && writer.exceeded,
}
}
struct BoundedWriter {
bytes: Vec<u8>,
limit: usize,
exceeded: bool,
}
impl BoundedWriter {
fn new(limit: usize) -> Self {
Self {
bytes: Vec::with_capacity(limit.min(8_192)),
limit,
exceeded: false,
}
}
}
impl Write for BoundedWriter {
fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
let remaining = self.limit.saturating_sub(self.bytes.len());
let accepted = buffer.len().min(remaining);
self.bytes.extend_from_slice(&buffer[..accepted]);
if accepted < buffer.len() {
self.exceeded = true;
return Err(io::Error::other("inspection bound exceeded"));
}
Ok(accepted)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
fn bounded_chars(value: &str, limit: usize) -> BoundedString {
let mut chars = value.chars();
let value = chars.by_ref().take(limit).collect::<String>();
BoundedString {
value,
truncated: chars.next().is_some(),
}
}
fn optional_bounded(value: Option<&str>) -> Evidence<BoundedString> {
value.map_or_else(
|| unknown("request field absent"),
|value| Evidence::Known {
value: bounded_chars(value, MAX_AUXILIARY_CHARS),
},
)
}
fn optional_copy<T: Copy>(value: Option<&T>) -> Evidence<T> {
value.map_or_else(
|| unknown("request field absent"),
|value| Evidence::Known { value: *value },
)
}
fn unknown<T>(reason: &str) -> Evidence<T> {
Evidence::Unknown {
reason: reason.to_string(),
}
}
fn render_bounded_evidence(out: &mut String, label: &str, evidence: &Evidence<BoundedString>) {
match evidence {
Evidence::Known { value } => out.push_str(&format!(
" {label}: {}\n {label} truncated: {}\n",
json_string(&value.value),
yes_no(value.truncated)
)),
Evidence::Unknown { reason } => {
out.push_str(&format!(" {label}: unknown ({reason})\n"));
}
}
}
fn render_bool_evidence(out: &mut String, label: &str, evidence: &Evidence<bool>) {
match evidence {
Evidence::Known { value } => out.push_str(&format!(" {label}: {value}\n")),
Evidence::Unknown { reason } => {
out.push_str(&format!(" {label}: unknown ({reason})\n"));
}
}
}
fn json_string(value: &str) -> String {
serde_json::to_string(value).unwrap_or_else(|_| "\"unavailable\"".to_string())
}
fn format_optional_usize(label: &str, value: Option<usize>) -> String {
value.map_or_else(
|| format!("{label}: unavailable\n"),
|value| format!("{label}: {value}\n"),
)
}
fn format_optional_string(label: &str, value: Option<&str>) -> String {
value.map_or_else(
|| format!("{label}: unavailable\n"),
|value| format!("{label}: {value}\n"),
)
}
const fn yes_no(value: bool) -> &'static str {
if value { "yes" } else { "no" }
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn tool(name: &str) -> Tool {
Tool {
tool_type: Some("function".to_string()),
name: name.to_string(),
description: "Read a file".to_string(),
input_schema: json!({"type": "object"}),
allowed_callers: None,
defer_loading: Some(false),
input_examples: None,
strict: Some(true),
cache_control: None,
}
}
#[test]
fn absent_field_stays_distinct_from_present_empty_array() {
let absent = ToolInspectionSnapshot::from_prepared_request("turn", 1, None);
let empty = ToolInspectionSnapshot::from_prepared_request("turn", 1, Some(&[]));
assert!(!absent.tools_field_present);
assert_eq!(absent.payload_json_bytes, None);
assert!(absent.active_tool_catalog_sha256.is_none());
assert!(empty.tools_field_present);
assert_eq!(empty.payload_json_bytes, Some(2));
assert!(empty.active_tool_catalog_sha256.is_some());
}
#[test]
fn catalog_digest_is_the_request_manifest_digest_not_a_second_definition() {
let tools = vec![tool("read_file"), tool("write_file")];
let snapshot = ToolInspectionSnapshot::from_prepared_request("turn", 1, Some(&tools));
assert_eq!(
snapshot.active_tool_catalog_sha256.as_deref(),
Some(crate::core::engine::preview::active_tool_catalog_sha256(&tools).as_str()),
);
let reordered = vec![tools[1].clone(), tools[0].clone()];
let reordered = ToolInspectionSnapshot::from_prepared_request("turn", 1, Some(&reordered));
assert_ne!(
snapshot.active_tool_catalog_sha256,
reordered.active_tool_catalog_sha256
);
}
#[test]
fn projection_preserves_known_false_and_marks_unknown() {
let snapshot =
ToolInspectionSnapshot::from_prepared_request("turn", 3, Some(&[tool("read_file")]));
let text = snapshot.render_text();
assert!(text.contains("deferred loading: false"), "{text}");
assert!(text.contains("strict: true"), "{text}");
assert!(text.contains("allowed callers: unknown (request field absent)"));
assert!(text.contains("Delivery: unknown"));
assert!(text.contains("Provider-wire tool payload: unavailable"));
}
fn facts(name: &str, plugin: bool, model_visible: bool) -> RegistryFacts {
RegistryFacts {
name: name.to_string(),
description: format!("{name} registry description"),
model_visible,
capabilities: vec!["ReadOnly".to_string()],
approval: "Auto".to_string(),
plugin,
}
}
fn surface() -> ToolSurfaceContext {
ToolSurfaceContext {
registry: vec![
facts("read_file", false, true),
facts("plugin_tool", true, true),
facts("hidden_alias", false, false),
facts("not_sent", false, true),
],
mcp_servers: BTreeMap::from([(
"mcp_my_server_read_file".to_string(),
"my_server".to_string(),
)]),
synthetic_names: vec!["tool_search".to_string()],
provider: ProviderAvailability::Available {
provider: "Deepseek".to_string(),
model: "deepseek-chat".to_string(),
},
}
}
#[test]
fn surface_context_turns_provenance_and_attribution_into_truth() {
let tools = vec![
tool("read_file"),
tool("plugin_tool"),
tool("mcp_my_server_read_file"),
tool("tool_search"),
tool("stranger"),
];
let surface = surface();
let snapshot = ToolInspectionSnapshot::from_prepared_request_with_surface(
"turn",
1,
Some(&tools),
Some(&surface),
);
let provenance = |name: &str| {
snapshot
.tools
.iter()
.find(|entry| entry.name.value == name)
.map(|entry| entry.provenance.clone())
.expect("projected tool")
};
for (name, expected) in [
("read_file", ToolProvenance::Builtin),
("plugin_tool", ToolProvenance::Plugin),
("mcp_my_server_read_file", ToolProvenance::Mcp),
("tool_search", ToolProvenance::Synthetic),
("stranger", ToolProvenance::Unknown),
] {
assert_eq!(
provenance(name),
Evidence::Known { value: expected },
"provenance for {name}"
);
}
let mcp = snapshot
.tools
.iter()
.find(|entry| entry.name.value == "mcp_my_server_read_file")
.expect("mcp tool");
assert_eq!(
mcp.mcp_server,
Evidence::Known {
value: BoundedString {
value: "my_server".to_string(),
truncated: false,
}
}
);
let read_file = snapshot
.tools
.iter()
.find(|entry| entry.name.value == "read_file")
.expect("read_file");
assert!(matches!(read_file.capabilities, Evidence::Known { .. }));
assert_eq!(
read_file.approval,
Evidence::Known {
value: BoundedString {
value: "Auto".to_string(),
truncated: false,
}
}
);
assert_eq!(read_file.model_visible, Evidence::Known { value: true });
let stranger = snapshot
.tools
.iter()
.find(|entry| entry.name.value == "stranger")
.expect("stranger");
assert!(matches!(stranger.capabilities, Evidence::Unknown { .. }));
assert!(matches!(stranger.approval, Evidence::Unknown { .. }));
assert_eq!(
snapshot.unavailable_for_this_request,
vec!["provider_wire_payload"]
);
assert!(snapshot.provider.is_available());
assert!(snapshot.registry_facts_present);
assert_eq!(snapshot.registry_tool_count, Evidence::Known { value: 4 });
let text = snapshot.render_text();
assert!(text.contains("provenance: synthetic"), "{text}");
assert!(text.contains("MCP server: \"my_server\""), "{text}");
assert!(text.contains("Provider: \"Deepseek\""), "{text}");
assert!(
text.contains("Provider-wire tool payload: unavailable"),
"{text}"
);
}
#[test]
fn registry_only_tools_are_counted_without_expanding_the_projection() {
let tools = vec![tool("read_file")];
let surface = surface();
let snapshot = ToolInspectionSnapshot::from_prepared_request_with_surface(
"turn",
1,
Some(&tools),
Some(&surface),
);
assert_eq!(snapshot.tools.len(), 1);
let Evidence::Known { value } = &snapshot.registry_only_tools else {
panic!("registry-only tools must be known when facts were captured");
};
assert_eq!(value.count, 2);
let rendered = value
.rendered
.iter()
.map(|entry| entry.value.as_str())
.collect::<Vec<_>>();
assert_eq!(rendered, vec!["plugin_tool", "not_sent"]);
assert!(snapshot.tools.iter().all(|entry| {
entry.visibility.in_request() && entry.visibility == ToolVisibility::Active
}));
}
#[test]
fn absent_surface_keeps_every_registry_derived_field_unknown() {
let tools = vec![tool("read_file")];
let snapshot = ToolInspectionSnapshot::from_prepared_request("turn", 1, Some(&tools));
assert_eq!(snapshot.provider, ProviderAvailability::Unknown);
assert!(!snapshot.registry_facts_present);
assert!(matches!(
snapshot.registry_tool_count,
Evidence::Unknown { .. }
));
assert!(matches!(
snapshot.registry_only_tools,
Evidence::Unknown { .. }
));
assert_eq!(
snapshot.unavailable_for_this_request,
vec![
"provider_wire_payload",
"provider",
"model",
"approval",
"provenance",
"capabilities",
]
);
let entry = &snapshot.tools[0];
for evidence in [
matches!(entry.provenance, Evidence::Unknown { .. }),
matches!(entry.mcp_server, Evidence::Unknown { .. }),
matches!(entry.capabilities, Evidence::Unknown { .. }),
matches!(entry.approval, Evidence::Unknown { .. }),
matches!(entry.model_visible, Evidence::Unknown { .. }),
] {
assert!(evidence);
}
assert!(entry.visibility.in_request());
assert!(snapshot.active_tool_catalog_sha256.is_some());
}
#[test]
fn provider_receipt_records_an_unresolved_client_without_borrowing_registry_truth() {
let tools = vec![tool("read_file")];
let surface = ToolSurfaceContext {
registry: vec![facts("read_file", false, true)],
provider: ProviderAvailability::Unavailable {
reason: "no model client resolved for this turn".to_string(),
},
..ToolSurfaceContext::default()
};
let snapshot = ToolInspectionSnapshot::from_prepared_request_with_surface(
"turn",
1,
Some(&tools),
Some(&surface),
);
assert!(!snapshot.provider.is_available());
assert_eq!(snapshot.provider.label(), "unavailable");
assert!(snapshot.unavailable_for_this_request.contains(&"provider"));
assert!(
!snapshot
.unavailable_for_this_request
.contains(&"provenance")
);
assert_eq!(
snapshot.tools[0].provenance,
Evidence::Known {
value: ToolProvenance::Builtin
}
);
}
#[test]
fn capture_and_rendering_are_bounded_with_explicit_receipts() {
let mut tools = (0..40)
.map(|index| {
let mut value = tool(&format!("tool_{index}"));
value.description = "x".repeat(MAX_DESCRIPTION_CHARS + 10);
value.input_schema = json!({"large": "y".repeat(MAX_SCHEMA_BYTES * 600)});
value
})
.collect::<Vec<_>>();
tools[0].allowed_callers = Some(
(0..20)
.map(|caller| format!("caller-{caller}-{}", "z".repeat(200)))
.collect(),
);
let snapshot = ToolInspectionSnapshot::from_prepared_request(
&"t".repeat(MAX_AUXILIARY_CHARS + 1),
1,
Some(&tools),
);
assert_eq!(snapshot.rendered_tool_count, MAX_RENDERED_TOOLS);
assert_eq!(snapshot.omitted_tool_count, 8);
assert!(snapshot.turn_id.truncated);
assert!(snapshot.tools[0].description.truncated);
assert!(snapshot.tools[0].input_schema_json.truncated);
assert_eq!(snapshot.payload_json_bytes, None);
assert!(snapshot.payload_measurement_status.contains("exceeds"));
assert!(snapshot.active_tool_catalog_sha256.is_some());
let json = snapshot.render_json().expect("bounded JSON");
assert!(
json.len() < 163_840,
"projection grew to {} bytes",
json.len()
);
}
}