lash-protocol-standard 0.1.0-alpha.63

Standard protocol (native provider tool calls) for the lash agent runtime.
Documentation
use lash_core::{ToolAvailabilityConfig, ToolDefinition, ToolScheduling};

pub fn batch_tool_definition() -> ToolDefinition {
    ToolDefinition::raw(
        "tool:batch",
        "batch",
        "Execute up to 25 independent tool calls concurrently. Calls start in parallel; ordering is not guaranteed. Calls past index 25 are rejected.",
        object_schema(
            serde_json::json!({
                "tool_calls": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 25,
                    "items": {
                        "type": "object",
                        "properties": {
                            "tool": { "type": "string" },
                            "parameters": { "type": "object", "additionalProperties": true }
                        },
                        "required": ["tool", "parameters"],
                        "additionalProperties": false
                    },
                    "description": "Array of 1-25 objects like { tool: \"read_file\", parameters: { path: \"src/main.rs\" } }. Use only for independent calls. Do not include another batch call. More than 25 calls is rejected as a tool error."
                }
            }),
            &["tool_calls"],
        ),
        batch_output_schema(),
    )
    .with_examples(vec![
            r#"await tools.batch({ tool_calls: [{ tool: "read_file", parameters: { path: "src/main.rs" } }, { tool: "grep", parameters: { query: "ToolProvider crates/lash/src/" } }] })?"#.to_string(),
        ])
    .with_availability(ToolAvailabilityConfig::callable())
    .with_scheduling(ToolScheduling::Parallel)
}

fn batch_output_schema() -> serde_json::Value {
    serde_json::json!({
        "type": "object",
        "properties": {
            "results": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "index": { "type": "integer", "minimum": 0 },
                        "tool": { "type": "string" },
                        "success": { "type": "boolean" },
                        "duration_ms": { "type": "integer", "minimum": 0 },
                        "result": {},
                        "error": {}
                    },
                    "required": ["index", "tool", "success", "duration_ms"],
                    "additionalProperties": false
                }
            }
        },
        "required": ["results"],
        "additionalProperties": false
    })
}

fn object_schema(properties: serde_json::Value, required: &[&str]) -> serde_json::Value {
    serde_json::json!({
        "type": "object",
        "properties": properties,
        "required": required,
        "additionalProperties": false,
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn batch_contract_documents_results_array() {
        let definition = batch_tool_definition();

        assert_eq!(
            definition.contract.output_schema["required"],
            serde_json::json!(["results"])
        );
        let rendered = definition.compact_contract().render_signature();
        assert!(rendered.contains("results"), "{rendered}");
    }
}