Skip to main content

typesec_agent/
interop.rs

1//! Wire-level interop: guard LLM tool calls from any agent framework.
2//!
3//! Agent frameworks (Pydantic AI, LangChain, the OpenAI and Anthropic SDKs)
4//! all share the same last-mile shape: the model emits a *tool call* — a tool
5//! name plus JSON arguments — and the host process decides whether to run it.
6//! That decision point is exactly where Typesec belongs, and it is the one
7//! place none of the frameworks guard for you.
8//!
9//! This module provides:
10//!
11//! - [`ToolCallRequest`] — a framework-neutral, normalized tool call.
12//! - [`ToolBinding`] — the declaration of how one tool maps onto the Typesec
13//!   `(action, resource)` plane, optionally taking the resource from a tool
14//!   argument.
15//! - [`ToolCallGuard`] — evaluates normalized calls against any
16//!   [`PolicyEngine`](typesec_core::policy::PolicyEngine), **deny-by-default**
17//!   for tools without a binding.
18//! - Dialect codecs ([`openai`], [`anthropic`], [`langchain`],
19//!   [`pydantic_ai`]) that parse each framework's wire shape into
20//!   [`ToolCallRequest`]s and render denials back in the shape the framework
21//!   expects (an error tool-result / retry part), so a blocked call flows back
22//!   to the model as feedback instead of crashing the run.
23//!
24//! ```text
25//! model output ─▶ dialect::parse_tool_calls ─▶ ToolCallGuard::check_all
26//!                                                   │ Allow ─▶ run the tool
27//!                                                   └ Deny  ─▶ dialect::denial ─▶ model
28//! ```
29//!
30//! The typed [`ProtectedTool`](crate::ProtectedTool) path remains the
31//! strongest boundary (a capability is required to *compile* the call); this
32//! module is the runtime bridge for tools that live on the other side of a
33//! JSON wire, where Rust types cannot reach.
34
35mod call;
36mod guard;
37mod taint;
38mod wire;
39
40pub mod anthropic;
41pub mod dialects;
42pub mod langchain;
43pub mod mcp;
44pub mod openai;
45pub mod pydantic_ai;
46
47pub use call::{GuardedToolCall, InteropError, ToolBinding, ToolCallRequest, ToolCallVerdict};
48pub use guard::ToolCallGuard;
49pub use taint::{TOOL_OUTPUT_KIND, TaintError};
50
51#[cfg(test)]
52mod tests;