roboticus 0.11.4

Autonomous agent runtime — HTTP API, CLI, WebSocket push, and migration engine
Documentation
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::sync::Arc;

use roboticus_agent::tools::{ToolContext, ToolRegistry};
use roboticus_core::InputAuthority;
use roboticus_core::config::PluginsConfig;
use roboticus_server::plugins::{init_plugin_registry, register_plugin_tools};

#[tokio::test]
async fn hello_world_plugin_round_trips_through_runtime_tool_registry() {
    let dir = tempfile::tempdir().expect("tempdir");
    let plugin_dir = dir.path().join("hello-world");
    fs::create_dir(&plugin_dir).expect("create plugin dir");

    fs::write(
        plugin_dir.join("plugin.toml"),
        r#"
name = "hello-world"
version = "0.1.0"
description = "Minimal integration test plugin"

[[tools]]
name = "hello_world"
description = "Returns a deterministic hello-world payload"
"#,
    )
    .expect("write plugin manifest");

    fs::write(
        plugin_dir.join("hello_world.sh"),
        r#"#!/bin/sh
echo "hello world from plugin"
"#,
    )
    .expect("write plugin script");

    let config = PluginsConfig {
        dir: PathBuf::from(dir.path()),
        allow: vec![],
        deny: vec![],
        strict_permissions: false,
        allowed_permissions: vec![],
    };

    let plugin_registry = init_plugin_registry(&config, HashMap::new()).await;
    assert_eq!(plugin_registry.plugin_count().await, 1);

    let mut tool_registry = ToolRegistry::new();
    register_plugin_tools(&mut tool_registry, Arc::clone(&plugin_registry)).await;

    let bridged_tool = tool_registry
        .get("hello_world")
        .expect("hello_world tool should be bridged");

    let ctx = ToolContext {
        session_id: "integration-session".to_string(),
        agent_id: "integration-agent".to_string(),
        agent_name: "Integration Agent".to_string(),
        authority: InputAuthority::Creator,
        workspace_root: dir.path().to_path_buf(),
        tool_allowed_paths: vec![],
        channel: None,
        db: None,
        sandbox: roboticus_agent::tools::ToolSandboxSnapshot::default(),
    };

    let result = bridged_tool
        .execute(serde_json::json!({}), &ctx)
        .await
        .expect("hello_world tool should execute");

    assert!(
        result.output.contains("hello world from plugin"),
        "unexpected plugin output: {}",
        result.output
    );
}