descry-tool-core 0.3.1

Core traits and types for descry-tool framework
Documentation
# descry-tool-core

[![Crates.io](https://img.shields.io/crates/v/descry-tool-core.svg)](https://crates.io/crates/descry-tool-core)
[![Documentation](https://docs.rs/descry-tool-core/badge.svg)](https://docs.rs/descry-tool-core)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Core traits and types for the descry-tool framework - a modern, async-first Rust framework for building LLM-compatible tools.

## Features

- **Unified async Tool trait** - Single trait for all tools, no SyncTool/AsyncTool separation
- **Arc<ToolContext>** - Thread-safe context that works seamlessly across await points
- **Compile-time registration** - Zero-cost tool registration using `inventory`
- **Thread-safe extensions** - Concurrent extensions using `DashMap`
- **Multi-protocol adapters** - Built-in support for MCP, OpenAI, and Anthropic
- **Tower Service integration** - Optional middleware ecosystem support
- **Auto-generated schemas** - Type-safe JSON Schema with thread-local caching
- **Error chaining** - Rich error types with `thiserror` and `#[source]` support

## Quick Start

### Define a Tool

```rust
use descry_tool_core::{Tool, ToolContext, ToolError};
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;
use std::sync::Arc;

#[derive(Deserialize, JsonSchema)]
struct AddParams {
    a: i32,
    b: i32,
}

#[derive(Serialize, JsonSchema)]
struct AddOutput {
    result: i32,
}

struct AddTool;

impl Tool for AddTool {
    type Params = AddParams;
    type Output = AddOutput;

    const NAME: &'static str = "add";
    const DESCRIPTION: &'static str = "Add two numbers";

    async fn call(
        _ctx: Arc<ToolContext>,
        params: Self::Params,
    ) -> Result<Self::Output, ToolError> {
        Ok(AddOutput {
            result: params.a + params.b,
        })
    }
}

// Register the tool
inventory::submit! {
    descry_tool_core::ToolMeta {
        name: AddTool::NAME,
        description: AddTool::DESCRIPTION,
        call: |ctx, params| {
            Box::pin(async move {
                let params: AddParams = serde_json::from_value(params)?;
                let result = <AddTool as Tool>::call(ctx, params).await?;
                Ok(serde_json::to_value(result)?)
            })
        },
        schema: || AddTool::schema(),
        examples: || AddTool::EXAMPLES,
    }
}
```

### Use the Tool

```rust
use descry_tool_core::{call_tool, tool_names, ToolContext};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    // List all registered tools
    let names = tool_names();
    println!("Available tools: {:?}", names);

    // Call a tool
    let ctx = Arc::new(ToolContext::new());
    let params = serde_json::json!({"a": 5, "b": 3});
    let result = call_tool("add", params, ctx).await.unwrap();
    println!("Result: {}", result);
}
```

## Core API

### Tool Trait

```rust
pub trait Tool: Send + Sync + 'static {
    type Params: DeserializeOwned + JsonSchema + Send + Sync + 'static;
    type Output: Serialize + JsonSchema + Send + Sync + 'static;

    const NAME: &'static str;
    const DESCRIPTION: &'static str;
    const EXAMPLES: &'static [(&'static str, &'static str)] = &[];

    fn schema() -> &'static serde_json::Value;
    
    async fn call(
        ctx: Arc<ToolContext>,
        params: Self::Params
    ) -> Result<Self::Output, ToolError>;
}
```

### Context System

```rust
use descry_tool_core::ToolContext;
use std::sync::Arc;

let ctx = Arc::new(ToolContext::new());

// Store extensions
#[derive(Debug)]
struct Database;
ctx.insert(Database);

// Retrieve extensions
let db: Arc<Database> = ctx.get().unwrap();
```

### Registry Functions

```rust
// Get all registered tools
pub fn all_tools() -> impl Iterator<Item = &'static ToolMeta>

// Find tool by name
pub fn find_tool(name: &str) -> Option<&'static ToolMeta>

// Call a tool
pub async fn call_tool(
    name: &str,
    params: serde_json::Value,
    ctx: Arc<ToolContext>
) -> Result<serde_json::Value, ToolError>

// Get tool names
pub fn tool_names() -> Vec<&'static str>

// Check if tool exists
pub fn tool_exists(name: &str) -> bool
```

## Multi-Protocol Adapters

### MCP (Model Context Protocol)

```rust
use descry_tool_core::adapters::{McpAdapter, ToolAdapter};

let mcp_spec = McpAdapter::to_spec(tool_meta);
// {
//   "name": "add",
//   "description": "Add two numbers",
//   "inputSchema": {...}
// }
```

### OpenAI Function Calling

```rust
use descry_tool_core::adapters::{OpenAiAdapter, ToolAdapter};

let openai_spec = OpenAiAdapter::to_spec(tool_meta);
// {
//   "type": "function",
//   "function": {
//     "name": "add",
//     "description": "Add two numbers",
//     "parameters": {...}
//   }
// }
```

### Anthropic (Claude)

```rust
use descry_tool_core::adapters::{AnthropicAdapter, ToolAdapter};

let anthropic_spec = AnthropicAdapter::to_spec(tool_meta);
// {
//   "name": "add",
//   "description": "Add two numbers",
//   "input_schema": {...}
// }
```

## Tower Service (Optional)

Enable the `tower` feature for middleware support:

```toml
[dependencies]
descry-tool-core = { version = "0.3", features = ["tower"] }
tower = "0.5"
```

```rust
use descry_tool_core::tower::{tool_service, ToolRequest};
use tower::{Service, ServiceBuilder};
use std::time::Duration;

let service = ServiceBuilder::new()
    .timeout(Duration::from_secs(30))
    .service(tool_service());

let response = service.call(request).await?;
```

## Error Handling

```rust
use descry_tool_core::ToolError;

match call_tool("add", params, ctx).await {
    Ok(result) => println!("Success: {:?}", result),
    Err(ToolError::ToolNotFound(name)) => {
        eprintln!("Tool '{}' not found", name);
    }
    Err(ToolError::InvalidParameters(msg)) => {
        eprintln!("Invalid parameters: {}", msg);
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}
```

## Examples

See the [examples](./examples/) directory:

- `basic.rs` - Basic tool definition and usage
- `macro_example.rs` - Using with `#[tool]` macro
- `complete_example.rs` - Multiple tools with error handling
- `multi_protocol.rs` - Multi-protocol adapter usage
- `tower_basic.rs` - Tower Service integration
- `tower_middleware.rs` - Tower middleware example
- `debug_schema.rs` - Schema generation debugging

## Related Crates

- [`descry-tool-macros`]https://crates.io/crates/descry-tool-macros - Procedural macros for simplified tool definition

## Requirements

- Rust 1.85.0+ (Edition 2024)

## License

MIT