Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- feature: mount in host runner #71

Merged
merged 11 commits into from
Nov 27, 2024
113 changes: 70 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,25 @@

[![Mutable.ai Auto Wiki](https://img.shields.io/badge/Auto_Wiki-Mutable.ai-blue)](https://wiki.mutable.ai/dcSpark/shinkai-tools)

Shinkai Tools serves as the ecosystem to execute Shinkai tools, provided by the Shinkai team or third-party developers, in a secure environment. It provides a sandboxed space for executing these tools,
Shinkai Tools serves as the ecosystem to execute Shinkai tools, provided by the Shinkai team or third-party developers, in a secure environment. It provides a sandboxed space for executing these tools,
ensuring that they run safely and efficiently, while also allowing for seamless integration with Rust code.

This repository is a comprehensive collection of tools and utilities designed to facilitate the integration of JavaScript and Rust code. It provides a framework for executing Deno scripts within a Rust environment, allowing for seamless communication and data exchange between the two languages.

The primary components of this repository include:

* `apps/shinkai-tool-*` These are small Deno tools designed to perform specific tasks. Each tool is a self-contained project with its own configuration and build process, allowing for easy maintenance and updates.
* `libs/shinkai-tools-builder` type definitions to make tools more readable and easy to code.
* `libs/shinkai-tools-runner` is a Rust library used to execute a tool in a secured and performant Deno environment, providing a safe and efficient way to run tools within the Shinkai ecosystem.
- `apps/shinkai-tool-*` These are small Deno tools designed to perform specific tasks. Each tool is a self-contained project with its own configuration and build process, allowing for easy maintenance and updates.
- `libs/shinkai-tools-builder` type definitions to make tools more readable and easy to code.
- `libs/shinkai-tools-runner` is a Rust library used to execute a tool in a secured and performant Deno environment, providing a safe and efficient way to run tools within the Shinkai ecosystem.

## Documentation

General Documentation: [https://docs.shinkai.com](https://docs.shinkai.com)

More In Depth Codebase Documentation (Mutable.ai): [https://wiki.mutable.ai/dcSpark/shinkai-tools](https://wiki.mutable.ai/dcSpark/shinkai-tools)

## Getting started

### Init Typescript side

```
# In windows admin privileges is required because rquickjs-sys uses a git patch
npm ci
Expand All @@ -30,54 +29,82 @@ npx nx run-many -t build
npx nx run-many -t test
```

## How to use a tool from Rust side (using shinkai_tools_runner)

To execute a tool from the Rust side, you can follow these steps:
#### Example Usage

1. First, ensure that the tool's JavaScript file is located in the correct directory as specified in the `Cargo.toml` file.
2. In your Rust code, import the necessary modules and create a new instance of the `Tool` struct.
3. Load the tool's JavaScript file using the `load` method, passing the path to the file as an argument.
4. Once the tool is loaded, you can call its functions using the `run` method, passing any required arguments as JSON strings.
To call a tool from the Rust side, you can use the following example:

Here's an example:
```rust
use shinkai_tools_runner::built_in_tools::get_tool;
use shinkai_tools_runner::tools::tool::Tool;
use shinkai_tools_runner::{Tool, CodeFiles};
use serde_json::json;

#[tokio::main]
async fn main() {
let tool_definition = get_tool("shinkai-tool-echo").unwrap();
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let run_result = tool
.run(serde_json::json!({ "message": "valparaíso" }), None)
.await
.unwrap();
println!("{}", run_result.data["message"]);
// > "Hello, world!"
}
```

Also you can run inline tools. The only needed structure is a run method (it can be sync or async) with two parameters:

```rust
// Define the inline tool's Deno code
let js_code = r#"
function run(configurations, params) {
return { message: `Hello, ${params.name}!` };
console.log("Environment variable:", Deno.env.get('MOUNT')); // rw files /path/to/mount1,/path/to/mount2
console.log("Environment variable:", Deno.env.get('ASSETS')); // ro files /path/to/asset1,/path/to/asset2
console.log("Environment variable:", Deno.env.get('HOME')); // rw files /path/to/home
console.log("Environment variable:", Deno.env.get('SHINKAI_NODE_LOCATION')); // https://host.docker.internal:9554 (if it's running in docker) or 127.0.0.2:9554 (if it's running in host)
return { message: `Echoing: ${params.message}` };
}
"#;
let tool = Tool::new(js_code.to_string(), serde_json::Value::Null, None);
let run_result = tool
.run(serde_json::json!({ "name": "world" }), None)
.await
.unwrap();
println!("{}", run_result.data["message"]);
// > "Hello, world!"
"#;

// Set up the code files for the tool
// It's important to note that the entrypoint must be the name of the file in the `files` map.
// In this case, the entrypoint is `main.ts` and it's mapped to the `js_code` variable.
// You can also include other files in the `files` map if your tool needs them.
let code_files = CodeFiles {
files: std::collections::HashMap::from([("main.ts".to_string(), js_code.to_string())]),
entrypoint: "main.ts".to_string(),
};

// Create a random file to be used as a mount point. Basically it's a file that could be read/write by the tool
let test_file_path = tempfile::NamedTempFile::new().unwrap().into_temp_path();
std::fs::create_dir_all(test_file_path.parent().unwrap()).unwrap();
println!("test file path: {:?}", test_file_path);
std::fs::write(&test_file_path, "1").unwrap();

// Create the tool instance
let tool = Tool::new(
code_files,
json!({}),
Some(DenoRunnerOptions {
context: ExecutionContext {
// Here you specify where the system will store all the files related to execute code
storage: execution_storage.into(),
// Here you specify the context id, which is a unique identifier for the execution context.
// Tools in the same context share the same storage.
// It creates a folder with the context id and all the files related to the execution are stored in it.
context_id: context_id.clone(),
// The execution id is a unique identifier for the execution of the tool
// It creates logs for every execution and stores them in the storage folder.
execution_id: execution_id.clone(),
// The code id is a unique identifier for the code being executed.
// Used to identify the tools that's logging in the same execution.
code_id: "js_code1".into(),
// Here you specify the files that will be mounted with read/write permissions into the Deno execution environment.
mount_files: vec![test_file_path.to_path_buf().clone()],

// Here you specify the files that will be mounted with read-only permissions into the Deno execution environment.
// assets_files: vec![test_file_path.to_path_buf().clone()],
..Default::default()
},
..Default::default()
});

// Run the tool with input data
let result = tool.run(None, json!({"message": "Hello, Shinkai!"}), None).await.unwrap();

// Print the output
println!("Tool output: {:?}", result.data["message"]); // Echoing: ${params.message}

// After the execution you can find logs in the storage folder, specifically in storage/{context_id}/logs/{execution_id}_....log
}
```

This example demonstrates how to set up and call a Shinkai tool from Rust, including how to pass input data and handle the output.

## Adding a New Shinkai Tool

To add a new Shinkai tool to this project, follow these simple steps:
Expand Down
6 changes: 6 additions & 0 deletions libs/shinkai-tools-runner/src/tools/deno_execution_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ impl DenoExecutionStorage {
e
})?;
}
log::info!("creating deno.json file");
let deno_json_path = self.code_folder_path.join("deno.json");
std::fs::write(&deno_json_path, "{}").map_err(|e| {
log::error!("failed to write deno.json file: {}", e);
e
})?;

log::info!(
"creating log file if not exists: {}",
Expand Down
Loading
Loading