clawseed-api — Core Trait Definitions¶
Overview¶
clawseed-api is the foundational crate of the entire project — zero implementation, trait definitions and shared types only. All other crates depend on it, while it depends on no business crate.
Core rule: Extensions import api; api never imports extensions.
Core Traits¶
Provider — LLM Inference Backend¶
#[async_trait]
pub trait Provider: Send + Sync {
async fn chat_with_system(&self, system_prompt: Option<&str>, message: &str, model: &str, temperature: Option<f64>) -> Result<String>;
async fn chat(&self, request: ChatRequest<'_>, model: &str, temperature: Option<f64>) -> Result<ChatResponse>;
fn supports_native_tools(&self) -> bool;
fn stream_chat(&self, request: ChatRequest<'_>, model: &str, temperature: Option<f64>, options: StreamOptions) -> BoxStream<'static, StreamResult<StreamEvent>>;
fn capabilities(&self) -> ProviderCapabilities;
// ... more methods with defaults
}
chat_with_system()— Core chat method; all other chat methods delegate to thischat()— Full chat with tool specs; returnsChatResponsewith optional tool callssupports_native_tools()— Whether the provider supports native tool calling protocol (e.g., Anthropic's tool_use)stream_chat()— Streaming variant returningBoxStream<StreamEvent>capabilities()— ReturnsProviderCapabilitiesincludingCacheStrategy- Providers without native tool support use
XmlToolDispatcher(◁▷ markers)
CacheStrategy — How a provider handles prompt caching:
pub enum CacheStrategy {
#[default]
None, // No explicit markers; automatic prefix caching with stable prompts
ExplicitAnthropic, // Anthropic-style cache_control:ephemeral or Bedrock CachePoint
}
pub struct ProviderCapabilities {
pub native_tool_calling: bool,
pub vision: bool,
pub cache_strategy: CacheStrategy,
}
None— Default. The system prompt is 100% stable across turns, so providers with automatic prefix caching (DeepSeek, OpenAI, Groq) work without any message-level transformation.ExplicitAnthropic— Anthropic and Bedrock injectcache_control: ephemeralmarkers orCachePointblocks within system messages. Used by Anthropic, Bedrock, and DeepSeek-anthropic providers.
Tool — Agent-Callable Capability¶
#[async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &str;
fn description(&self) -> &str;
fn parameters_schema(&self) -> serde_json::Value;
async fn execute(&self, args: serde_json::Value, ctx: &dyn ToolContext) -> anyhow::Result<ToolResult>;
fn spec(&self) -> ToolSpec { /* default implementation */ }
}
name()— Unique tool identifierdescription()— Tool description for the LLMparameters_schema()— JSON Schema parameter definitionexecute()— Execute tool logic, access runtime capabilities viaToolContextspec()— GenerateToolSpecfor LLM registration
Hook — Tool Call Interceptor¶
pub trait Hook: Send + Sync {
fn before_tool_call(&self, call: &mut ToolCall) -> HookResult;
fn after_tool_call(&self, result: &ToolExecutionResult) -> HookResult;
}
before_tool_call()— Called before tool execution; can cancel, modify, or allowafter_tool_call()— Called after tool execution; for observation and auditing
pub enum HookResult {
Continue, // Allow execution
Cancel(String), // Cancel execution with a reason
Modify(ToolCall), // Modify the tool call (name/arguments)
}
Memory — Conversation Memory Backend¶
#[async_trait]
pub trait Memory: Send + Sync {
fn name(&self) -> &str;
async fn store(&self, key: &str, content: &str, category: MemoryCategory, session_id: Option<&str>) -> Result<()>;
async fn recall(&self, query: &str, limit: usize, session_id: Option<&str>, since: Option<&str>, until: Option<&str>) -> Result<Vec<MemoryEntry>>;
async fn get(&self, key: &str) -> Result<Option<MemoryEntry>>;
async fn list(&self, category: Option<&MemoryCategory>, session_id: Option<&str>) -> Result<Vec<MemoryEntry>>;
async fn forget(&self, key: &str) -> Result<bool>;
async fn count(&self) -> Result<usize>;
async fn health_check(&self) -> bool;
// ... more methods with defaults: purge_namespace, purge_session, recall_namespaced, export, store_with_metadata
}
ToolRegistry — Unified Tool Registration¶
pub trait ToolRegistry: Send + Sync {
fn register(&self, tool: Box<dyn Tool>, source: ToolSource) -> bool;
fn unregister(&self, name: &str) -> bool;
fn get_tool(&self, name: &str) -> Option<Arc<dyn Tool>>;
fn tool_specs(&self) -> Vec<ToolSpec>;
fn get_entry(&self, name: &str) -> Option<ToolEntry>;
fn tool_names(&self) -> Vec<String>;
fn register_or_replace(&self, tool: Box<dyn Tool>, source: ToolSource) -> Option<ToolEntry>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
}
register()— Register a tool; returns false if one with the same name already existsunregister()— Remove a tool by nameget_tool()— Look up by name, returnsArc<dyn Tool>(safe to share across async contexts)tool_specs()— Get all tool specs (cached) for LLM registrationregister_or_replace()— Register or replace a tool with the same name (used for remote tool reconnection)
/// Provenance of a registered tool
pub enum ToolSource {
BuiltIn, // Built-in tool
Mcp { server: String }, // Tool from an MCP server
Remote { session: String }, // Tool registered by a remote client
}
/// Tool entry metadata
pub struct ToolEntry {
pub source: ToolSource,
}
Shared Types¶
Message Types¶
pub struct ChatMessage {
pub role: String, // "system" / "user" / "assistant" / "tool"
pub content: String,
}
pub struct ChatResponse {
pub text: Option<String>,
pub tool_calls: Vec<ToolCall>,
pub usage: Option<TokenUsage>,
pub reasoning_content: Option<String>,
}
Tool Types¶
// From provider.rs — LLM-requested tool call
pub struct ToolCall {
pub id: String,
pub name: String,
pub arguments: String, // JSON string
}
// From hook.rs — hook interception tool call
pub struct ToolCall {
pub id: String,
pub name: String,
pub arguments: Value, // Parsed JSON value
}
pub struct ToolResult {
pub success: bool,
pub output: String,
pub error: Option<String>,
}
pub struct ToolSpec {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
Task-Local Storage¶
clawseed-api uses task-local variables for cross-call context:
TOOL_CHOICE_OVERRIDE— Override tool selection strategy
Dependencies¶
Only depends on:
- async-trait — Async trait support
- serde / serde_json — Serialization
- anyhow — Error handling
- tokio — Task-local storage
- futures-util — Stream types