jules-core 0.1.1

Core abstractions and traits for Jules-SDK
#![cfg(feature = "tools")]

use jules_core::errors::ToolError;
use jules_core::message::{Message, Role};
use jules_core::tool::{Tool, ToolCall, ToolCallInfo, ToolParameter, ToolParameters, ToolRegistry};
use std::collections::HashMap;
use std::future::Future;

struct WeatherTool;

impl Tool for WeatherTool {
    fn name(&self) -> &'static str {
        "get_weather"
    }

    fn description(&self) -> &'static str {
        "Gets the weather for a location."
    }

    fn parameters(&self) -> ToolParameters {
        let mut properties = HashMap::new();
        properties.insert(
            "location".to_string(),
            ToolParameter {
                param_type: "string".to_string(),
                description: Some("The city name".to_string()),
            },
        );
        ToolParameters {
            properties,
            required: vec!["location".to_string()],
        }
    }

    fn call(&self, args: &str) -> impl Future<Output = Result<String, ToolError>> + Send {
        let args = args.to_string();
        async move {
            if args.contains("London") {
                Ok("Rainy".to_string())
            } else {
                Ok("Sunny".to_string())
            }
        }
    }
}

#[tokio::test]
async fn test_tool_workflow() {
    let mut registry = ToolRegistry::new();
    registry.register(WeatherTool);

    let tool_call = ToolCall {
        function: ToolCallInfo {
            id: "call_123".to_string(),
            name: "get_weather".to_string(),
            arguments: r#"{"location": "London"}"#.to_string(),
        },
        tool_type: "function".to_string(),
    };

    let msg = Message::new(Role::Assistant, "").with_tool_calls(vec![tool_call.clone()]);

    assert!(msg.tool_calls().is_some());
    assert_eq!(msg.tool_calls().unwrap().len(), 1);

    let called_tool = registry
        .get(&tool_call.function.name)
        .expect("tool not found");
    let result = called_tool
        .call_dyn(&tool_call.function.arguments)
        .await
        .unwrap();

    assert_eq!(result, "Rainy");

    let tool_msg = Message::new(Role::Tool, result).with_tool_call_id("call_123");

    assert_eq!(tool_msg.role(), &Role::Tool);
    assert_eq!(tool_msg.tool_call_id(), Some("call_123"));
}