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: tools backend as tool argument #33

Merged
merged 3 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/shinkai-tools-runner/src/built_in_tools.test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::built_in_tools::{get_tool, get_tools};
async fn get_tools_all_load() {
let tools = get_tools();
for (tool_name, tool_definition) in tools {
let mut tool_instance = crate::tools::tool::Tool::new(tool_definition.code.unwrap(), Value::Null);
let mut tool_instance = crate::tools::tool::Tool::new(tool_definition.code.unwrap(), Value::Null, None);
let defintion = tool_instance
.get_definition()
.await;
Expand Down
13 changes: 12 additions & 1 deletion libs/shinkai-tools-runner/src/lib.test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ async fn shinkai_tool_echo() {
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)
Expand All @@ -21,6 +22,7 @@ async fn shinkai_tool_weather_by_city() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::json!({ "apiKey": "63d35ff6068c3103ccd1227526935675" }),
None,
);
let run_result = tool
.run(serde_json::json!({ "city": "valparaíso" }), None)
Expand Down Expand Up @@ -55,7 +57,7 @@ async fn shinkai_tool_inline() {

globalThis.tool = { Tool };
"#;
let tool = Tool::new(js_code.to_string(), serde_json::Value::Null);
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
Expand All @@ -69,6 +71,7 @@ async fn shinkai_tool_web3_eth_balance() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let run_result = tool
.run(
Expand All @@ -86,6 +89,7 @@ async fn shinkai_tool_web3_eth_uniswap() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let run_result = tool
.run(
Expand All @@ -109,6 +113,7 @@ async fn shinkai_tool_download_page() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let run_result = tool
.run(
Expand Down Expand Up @@ -178,6 +183,7 @@ async fn shinkai_tool_download_page_stack_overflow() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
tool.run(
serde_json::json!({
Expand All @@ -200,6 +206,7 @@ async fn shinkai_tool_leiden() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let edges = vec![
(2, 1, 1),
Expand Down Expand Up @@ -303,6 +310,7 @@ async fn shinkai_tool_duckduckgo_search() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::Value::Null,
None,
);
let run_result = tool
.run(
Expand All @@ -328,6 +336,7 @@ async fn shinkai_tool_playwright_example() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::json!({ "chromePath": std::env::var("CHROME_PATH").ok().unwrap_or("".to_string()) }),
None,
);
let run_result = tool
.run(
Expand All @@ -353,6 +362,7 @@ async fn shinkai_tool_defillama_lending_tvl_rankings() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::json!({ "chromePath": std::env::var("CHROME_PATH").ok().unwrap_or("".to_string()) }),
None,
);
let run_result = tool.run(serde_json::json!({ "all": true }), None).await;
assert!(run_result.is_ok());
Expand All @@ -365,6 +375,7 @@ async fn shinkai_tool_aave_loan_requester() {
let tool = Tool::new(
tool_definition.code.clone().unwrap(),
serde_json::json!({ "chromePath": std::env::var("CHROME_PATH").ok().unwrap_or("".to_string()) }),
None,
);
let run_result = tool
.run(
Expand Down
1 change: 1 addition & 0 deletions libs/shinkai-tools-runner/src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod tool;
pub mod run_result;
pub mod tool_definition;
pub mod execution_error;
pub mod shinkai_tools_backend_options;
pub mod shinkai_tools_backend;
67 changes: 42 additions & 25 deletions libs/shinkai-tools-runner/src/tools/shinkai_tools_backend.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use std::process::{Child, Command};

use super::shinkai_tools_backend_options::ShinkaiToolsBackendOptions;

#[derive(Default)]
pub struct ShinkaiToolsBackend {
child: Option<Child>,
}

impl Default for ShinkaiToolsBackend {
fn default() -> Self {
Self { child: None }
}
options: ShinkaiToolsBackendOptions,
}

impl ShinkaiToolsBackend {
fn new() -> Self {
ShinkaiToolsBackend::default()
pub fn new(options: ShinkaiToolsBackendOptions) -> Self {
ShinkaiToolsBackend {
options,
..Default::default()
}
}

pub async fn run(&mut self) -> Result<(), std::io::Error> {
Expand All @@ -21,37 +22,53 @@ impl ShinkaiToolsBackend {
self.kill().await?;
}

// Spawn the child process using native spawn
let child_process = Command::new("./shinkai-tools-runner-resources/shinkai-tools-backend").spawn().map_err(|e| {
println!("Error spawning child process: {}", e);
e
})?;
let child_process = Command::new(self.options.binary_path.clone())
.env("PORT", self.options.api_port.to_string())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.map_err(|e| {
println!("Error spawning child process: {}", e);
e
})?;
let pid = child_process.id();
self.child = Some(child_process);
println!("Started new child process with PID: {}", pid);

let client = reqwest::Client::new();

// Wait for the /health endpoint to respond with 200
let health_check_url = "http://127.0.0.1:3000/health";
let health_check_url = format!("http://127.0.0.1:{}/health", self.options.api_port).to_string();
let mut retries = 5;
while retries > 0 {
match client.get(health_check_url).send().await {
Ok(response) if response.status().is_success() => {
println!("Health check successful.");
break;
match client.get(health_check_url.clone()).send().await {
Ok(response) => {
if response.status().is_success() {
println!("shinkai-tools-backend /health successful.");
break;
} else {
println!(
"shinkai-tools-backend /health failed status: {}, code: {}, text: {}, retrying...",
response.status(),
response.status().as_u16(),
response.text().await.unwrap_or_else(|_| "".to_string())
);
}
}
Err(e) => {
println!("Health check failed: {}, retrying...", e);
}
_ => {
println!(
"Health check response was not successful, retries left: {}",
retries
);
println!("shinkai-tools-backend /health failed: {}, retrying...", e);
}
}
retries -= 1;
if retries <= 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"shinkai-tools-backend /health timeout after {} retries",
5 - retries
),
));
}
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
}
Ok(())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::path::PathBuf;

#[derive(Clone)]
pub struct ShinkaiToolsBackendOptions {
pub binary_path: PathBuf,
pub api_port: u16,
}

impl Default for ShinkaiToolsBackendOptions {
fn default() -> Self {
Self {
binary_path: PathBuf::from("./shinkai-tools-runner-resources/shinkai-tools-backend"),
api_port: 9650,
}
}
}
26 changes: 18 additions & 8 deletions libs/shinkai-tools-runner/src/tools/tool.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
use std::time::Duration;
use std::{path::PathBuf, time::Duration};

use reqwest::{header, Client};
use serde_json::Value;

use super::{
execution_error::ExecutionError, run_result::RunResult,
shinkai_tools_backend::ShinkaiToolsBackend, tool_definition::ToolDefinition,
execution_error::ExecutionError,
run_result::RunResult,
shinkai_tools_backend::{self, ShinkaiToolsBackend},
shinkai_tools_backend_options::ShinkaiToolsBackendOptions,
tool_definition::ToolDefinition,
};

pub struct Tool {
tool_backend_url: String,
code: String,
configurations: Value,
http_client: Client,
shinkai_tools_backend_options: ShinkaiToolsBackendOptions,
}

impl Tool {
pub const MAX_EXECUTION_TIME_MS_INTERNAL_OPS: u64 = 1000;

pub fn new(code: String, configurations: Value) -> Self {
pub fn new(
code: String,
configurations: Value,
shinkai_tools_backend_options: Option<ShinkaiToolsBackendOptions>,
) -> Self {
let options = shinkai_tools_backend_options.unwrap_or_default();
Tool {
tool_backend_url: "http://127.0.0.1:3000".to_string(),
tool_backend_url: format!("http://127.0.0.1:{}", options.api_port).to_string(),
code,
configurations,
http_client: Self::build_http_client(),
shinkai_tools_backend_options: options,
}
}

Expand Down Expand Up @@ -86,7 +96,7 @@ impl Tool {
}

pub async fn get_definition(&mut self) -> Result<ToolDefinition, ExecutionError> {
let mut shinkai_tool_backend = ShinkaiToolsBackend::default();
let mut shinkai_tool_backend = ShinkaiToolsBackend::new(self.shinkai_tools_backend_options.clone());
let _ = shinkai_tool_backend.run().await;
let result = self.internal_get_definition().await;
let _ = shinkai_tool_backend.kill().await;
Expand Down Expand Up @@ -156,8 +166,8 @@ impl Tool {
parameters: Value,
max_execution_time_s: Option<u64>,
) -> Result<RunResult, ExecutionError> {
let mut shinkai_tool_backend = ShinkaiToolsBackend::default();
let _ = shinkai_tool_backend.run().await;
let mut shinkai_tool_backend = ShinkaiToolsBackend::new(self.shinkai_tools_backend_options.clone());
shinkai_tool_backend.run().await.map_err(|e| ExecutionError::new(format!("Failed to run shinkai tool backend: {}", e), None))?;
let result = self.internal_run(parameters, max_execution_time_s).await;
let _ = shinkai_tool_backend.kill().await;
result
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shinkai_protocol/source",
"version": "0.7.4",
"version": "0.7.5",
"description": "This repository 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.",
"main": "index.js",
"author": "",
Expand Down
Loading