From 431b69e261b9cf9179f30bc62166708de5b2e998 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Wed, 15 Jan 2025 16:19:49 +0700 Subject: [PATCH 01/11] feat: onchain system prompt --- rig-core/Cargo.toml | 1 + rig-core/src/providers/eternalai.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/rig-core/Cargo.toml b/rig-core/Cargo.toml index 1afd7c0..202b56e 100644 --- a/rig-core/Cargo.toml +++ b/rig-core/Cargo.toml @@ -28,6 +28,7 @@ glob = "0.3.1" lopdf = { version = "0.34.0", optional = true } rayon = { version = "1.10.0", optional = true} worker = { version = "0.5", optional = true } +ethers = "2.0.14" [dev-dependencies] anyhow = "1.0.75" diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index fc91b28..b0da7bd 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -9,6 +9,7 @@ //! let gpt4o = client.completion_model(eternalai::NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8); //! ``` +use std::sync::Arc; use crate::{ agent::AgentBuilder, completion::{self, CompletionError, CompletionRequest}, @@ -20,6 +21,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::time::Duration; +use ethers::prelude::*; +use crate::tool::ToolDyn; // ================================================================ // Main EternalAI Client @@ -331,6 +334,22 @@ pub fn get_chain_id(key: &str) -> Option<&str> { None } +pub async fn get_on_chain_system_prompt() -> &'static str { + abigen!( + MyContract, + r#" + [{"inputs": [{"internalType": "uint256", "name": "_agentId", "type": "uint256"}], "name": "getAgentSystemPrompt", "outputs": [{"internalType": "bytes[]", "name": "","type": "bytes[]"}], "stateMutability": "view", "type": "function"}] + "# + ); + // Connect to an Ethereum node + let provider = Provider::::try_from("https://mainnet.base.org/")?; + let client = Arc::new(provider); + let contract_address: Address = "0xAed016e060e2fFE3092916b1650Fc558D62e1CCC".parse()?; + let contract = MyContract::new(contract_address, client); + let value: U256 = contract.get_agent_system_prompt(U256::from(1)).call().await; + return ""; +} + #[derive(Debug, Deserialize)] pub struct CompletionResponse { pub id: String, From 6a8dd628369ce583ca48d9e11e5a2b95ff3db64a Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Thu, 16 Jan 2025 11:15:55 +0700 Subject: [PATCH 02/11] feat: onchain system prompt --- rig-core/src/providers/eternalai.rs | 93 ++++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index b0da7bd..abe0759 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -9,7 +9,6 @@ //! let gpt4o = client.completion_model(eternalai::NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8); //! ``` -use std::sync::Arc; use crate::{ agent::AgentBuilder, completion::{self, CompletionError, CompletionRequest}, @@ -17,18 +16,22 @@ use crate::{ extractor::ExtractorBuilder, json_utils, Embed, }; +use ethers::prelude::*; +use reqwest::get; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; +use std::ffi::c_uint; +use std::sync::Arc; use std::time::Duration; -use ethers::prelude::*; -use crate::tool::ToolDyn; // ================================================================ // Main EternalAI Client // ================================================================ const ETERNALAI_API_BASE_URL: &str = "https://api.eternalai.org/v1"; - +const IPFS: &str = "ipfs://"; +const LIGHTHOUSE_IPFS: &str = "https://gateway.lighthouse.storage/ipfs/"; +const GCS_ETERNAL_AI_BASE_URL: &str = "https://cdn.eternalai.org/upload/"; #[derive(Clone)] pub struct Client { base_url: String, @@ -334,7 +337,11 @@ pub fn get_chain_id(key: &str) -> Option<&str> { None } -pub async fn get_on_chain_system_prompt() -> &'static str { +pub async fn get_on_chain_system_prompt( + rpc_url: &str, + contract_addr: &str, + agent_id: c_uint, +) -> Option { abigen!( MyContract, r#" @@ -342,12 +349,53 @@ pub async fn get_on_chain_system_prompt() -> &'static str { "# ); // Connect to an Ethereum node - let provider = Provider::::try_from("https://mainnet.base.org/")?; + let provider = Provider::::try_from(rpc_url).expect("Failed to parse url"); let client = Arc::new(provider); - let contract_address: Address = "0xAed016e060e2fFE3092916b1650Fc558D62e1CCC".parse()?; + let contract_address: Address = contract_addr.parse().expect("invalid contract address"); let contract = MyContract::new(contract_address, client); - let value: U256 = contract.get_agent_system_prompt(U256::from(1)).call().await; - return ""; + let system_prompts: Vec = contract + .get_agent_system_prompt(U256::from(agent_id)) + .call() + .await + .expect("invalid agent system prompt"); + + let decoded_strings: Vec = system_prompts + .iter() + .map(|bytes| { + String::from_utf8(bytes.to_vec()).unwrap_or_else(|_| "[Invalid UTF-8]".to_string()) + }) + .collect(); + + for prompt in decoded_strings { + println!("system prompt : {}", prompt); + return fetch_on_chain_system_prompt(&*prompt).await; + } + None +} + +pub async fn fetch_on_chain_system_prompt(content: &str) -> Option { + if content.contains(IPFS) { + let light_house = content.replace(IPFS, LIGHTHOUSE_IPFS); + println!("light_house : {}", light_house); + let mut response = get(light_house).await.unwrap(); + if response.status().is_success() { + let body = response.text().await.unwrap(); + println!("light_house body: {}", body); + return Some(body); + } else { + let gcs = content.replace(IPFS, GCS_ETERNAL_AI_BASE_URL); + println!("gcs: {}", gcs); + response = get(gcs).await.unwrap(); + if response.status().is_success() { + let body = response.text().await.unwrap(); + println!("gcs body: {}", body); + return Some(body); + } else { + return None; + } + } + } + Some(content.to_string()) } #[derive(Debug, Deserialize)] @@ -489,6 +537,31 @@ impl completion::CompletionModel for CompletionModel { vec![] }; + println!("Try to get on-chain system prompt"); + let eternal_ai_rpc = std::env::var("ETERNALAI_RPC_URL").unwrap_or_else(|_| "".to_string()); + let eternal_ai_contract = + std::env::var("ETERNALAI_AGENT_CONTRACT_ADDRESS").unwrap_or_else(|_| "".to_string()); + let eternal_ai_agent_id = + std::env::var("ETERNALAI_AGENT_ID").unwrap_or_else(|_| "".to_string()); + if !eternal_ai_rpc.is_empty() + && !eternal_ai_contract.is_empty() + && !eternal_ai_agent_id.is_empty() + { + println!( + "get on-chain system prompt with {}, {}, {}", + eternal_ai_rpc, eternal_ai_contract, eternal_ai_agent_id + ); + let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); + let prompt = + get_on_chain_system_prompt(&*eternal_ai_rpc, &*eternal_ai_contract, c_value).await; + if !prompt.is_none() { + full_history.push(completion::Message { + role: "system".into(), + content: prompt.unwrap(), + }); + } + } + // Extend existing chat history full_history.append(&mut completion_request.chat_history); @@ -524,6 +597,8 @@ impl completion::CompletionModel for CompletionModel { }) }; + println!("request: {:?}", request.to_string()); + let response = self .client .post("/chat/completions") From 6d20b6925dfca1a76a48e4b89782503bc4dc3364 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Thu, 16 Jan 2025 11:21:10 +0700 Subject: [PATCH 03/11] feat: eternal-ai on-chain system prompt --- rig-core/src/providers/eternalai.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index abe0759..7c6b10f 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -343,7 +343,7 @@ pub async fn get_on_chain_system_prompt( agent_id: c_uint, ) -> Option { abigen!( - MyContract, + SystemPromptManagementContract, r#" [{"inputs": [{"internalType": "uint256", "name": "_agentId", "type": "uint256"}], "name": "getAgentSystemPrompt", "outputs": [{"internalType": "bytes[]", "name": "","type": "bytes[]"}], "stateMutability": "view", "type": "function"}] "# @@ -352,7 +352,7 @@ pub async fn get_on_chain_system_prompt( let provider = Provider::::try_from(rpc_url).expect("Failed to parse url"); let client = Arc::new(provider); let contract_address: Address = contract_addr.parse().expect("invalid contract address"); - let contract = MyContract::new(contract_address, client); + let contract = SystemPromptManagementContract::new(contract_address, client); let system_prompts: Vec = contract .get_agent_system_prompt(U256::from(agent_id)) .call() From 5a70ec0f077707d40453200544a202b1742047ca Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Thu, 16 Jan 2025 11:43:25 +0700 Subject: [PATCH 04/11] feat: eternal-ai on-chain system prompt --- rig-core/src/providers/eternalai.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index 7c6b10f..8636254 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -366,9 +366,10 @@ pub async fn get_on_chain_system_prompt( }) .collect(); - for prompt in decoded_strings { + if !decoded_strings.is_empty() { + let prompt = decoded_strings[0].clone(); println!("system prompt : {}", prompt); - return fetch_on_chain_system_prompt(&*prompt).await; + return fetch_on_chain_system_prompt(&prompt).await; } None } @@ -553,12 +554,18 @@ impl completion::CompletionModel for CompletionModel { ); let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); let prompt = - get_on_chain_system_prompt(&*eternal_ai_rpc, &*eternal_ai_contract, c_value).await; - if !prompt.is_none() { - full_history.push(completion::Message { - role: "system".into(), - content: prompt.unwrap(), - }); + get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value).await; + match prompt { + None => { + println!("on-chain sytem prompt is none") + } + Some(value) => { + let temp = completion::Message { + role: "system".into(), + content: value, + }; + full_history.push(temp); + } } } From 2bf4758cd48e7ebcd3eb55c7ebd428d614b49588 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 10:01:29 +0700 Subject: [PATCH 05/11] feat: eternal-ai on-chain system prompt --- rig-core/src/providers/eternalai.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index 8636254..0af6e23 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -24,6 +24,7 @@ use serde_json::{json, Value}; use std::ffi::c_uint; use std::sync::Arc; use std::time::Duration; +use tracing::trace; // ================================================================ // Main EternalAI Client @@ -368,7 +369,7 @@ pub async fn get_on_chain_system_prompt( if !decoded_strings.is_empty() { let prompt = decoded_strings[0].clone(); - println!("system prompt : {}", prompt); + tracing::info!("system prompt : {}", prompt); return fetch_on_chain_system_prompt(&prompt).await; } None @@ -548,16 +549,18 @@ impl completion::CompletionModel for CompletionModel { && !eternal_ai_contract.is_empty() && !eternal_ai_agent_id.is_empty() { - println!( + tracing::info!( "get on-chain system prompt with {}, {}, {}", - eternal_ai_rpc, eternal_ai_contract, eternal_ai_agent_id + eternal_ai_rpc, + eternal_ai_contract, + eternal_ai_agent_id ); let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); let prompt = get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value).await; match prompt { None => { - println!("on-chain sytem prompt is none") + tracing::info!("on-chain sytem prompt is none") } Some(value) => { let temp = completion::Message { @@ -604,7 +607,7 @@ impl completion::CompletionModel for CompletionModel { }) }; - println!("request: {:?}", request.to_string()); + tracing::debug!("request: {:?}", request.to_string()); let response = self .client From eb88bf6a1e449a9b1830e4aabe413aec4bd9e0ea Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 10:33:37 +0700 Subject: [PATCH 06/11] feat: eternal-ai on-chain system prompt --- rig-core/examples/agent_with_eternalai.rs | 3 ++ rig-core/src/providers/eternalai.rs | 39 +++++++++++++---------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/rig-core/examples/agent_with_eternalai.rs b/rig-core/examples/agent_with_eternalai.rs index 56bd45d..83fa1a8 100644 --- a/rig-core/examples/agent_with_eternalai.rs +++ b/rig-core/examples/agent_with_eternalai.rs @@ -4,6 +4,9 @@ use rig::{completion::Prompt, providers}; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::DEBUG) // Đặt mức độ tối đa là DEBUG + .init(); println!("Running basic agent with eternalai"); basic_eternalai().await?; diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index 0af6e23..453bff1 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -24,7 +24,6 @@ use serde_json::{json, Value}; use std::ffi::c_uint; use std::sync::Arc; use std::time::Duration; -use tracing::trace; // ================================================================ // Main EternalAI Client @@ -342,7 +341,7 @@ pub async fn get_on_chain_system_prompt( rpc_url: &str, contract_addr: &str, agent_id: c_uint, -) -> Option { +) -> Result, String> { abigen!( SystemPromptManagementContract, r#" @@ -350,15 +349,18 @@ pub async fn get_on_chain_system_prompt( "# ); // Connect to an Ethereum node - let provider = Provider::::try_from(rpc_url).expect("Failed to parse url"); + let provider = + Provider::::try_from(rpc_url).map_err(|e| format!("Failed to parse url: {}", e))?; let client = Arc::new(provider); - let contract_address: Address = contract_addr.parse().expect("invalid contract address"); + let contract_address: Address = contract_addr + .parse() + .map_err(|e| format!("invalid contract address: {}", e))?; let contract = SystemPromptManagementContract::new(contract_address, client); let system_prompts: Vec = contract .get_agent_system_prompt(U256::from(agent_id)) .call() .await - .expect("invalid agent system prompt"); + .map_err(|e| format!("invalid agent system prompt: {}", e))?; let decoded_strings: Vec = system_prompts .iter() @@ -369,28 +371,28 @@ pub async fn get_on_chain_system_prompt( if !decoded_strings.is_empty() { let prompt = decoded_strings[0].clone(); - tracing::info!("system prompt : {}", prompt); - return fetch_on_chain_system_prompt(&prompt).await; + tracing::debug!("system prompt : {}", prompt); + return Ok(fetch_on_chain_or_ipfs_system_prompt(&prompt).await); } - None + Ok(None) } -pub async fn fetch_on_chain_system_prompt(content: &str) -> Option { +pub async fn fetch_on_chain_or_ipfs_system_prompt(content: &str) -> Option { if content.contains(IPFS) { let light_house = content.replace(IPFS, LIGHTHOUSE_IPFS); - println!("light_house : {}", light_house); + tracing::debug!("light_house : {}", light_house); let mut response = get(light_house).await.unwrap(); if response.status().is_success() { let body = response.text().await.unwrap(); - println!("light_house body: {}", body); + tracing::debug!("light_house body: {}", body); return Some(body); } else { let gcs = content.replace(IPFS, GCS_ETERNAL_AI_BASE_URL); - println!("gcs: {}", gcs); + tracing::debug!("gcs: {}", gcs); response = get(gcs).await.unwrap(); if response.status().is_success() { let body = response.text().await.unwrap(); - println!("gcs body: {}", body); + tracing::debug!("gcs body: {}", body); return Some(body); } else { return None; @@ -557,7 +559,12 @@ impl completion::CompletionModel for CompletionModel { ); let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); let prompt = - get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value).await; + match get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value) + .await + { + Ok(value) => value, + Err(e) => return Err(CompletionError::ProviderError(e)), + }; match prompt { None => { tracing::info!("on-chain sytem prompt is none") @@ -632,10 +639,10 @@ impl completion::CompletionModel for CompletionModel { match &response.onchain_data { Some(data) => { let onchain_data = serde_json::to_string_pretty(data)?; - println!("onchain_data: {}", onchain_data); + tracing::info!("onchain_data: {}", onchain_data); } None => { - println!("onchain_data: None"); + tracing::info!("onchain_data: None"); } } response.try_into() From b47aa69b899b60d67bcd7e39e2d3a01fb5c8adb0 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 11:20:07 +0700 Subject: [PATCH 07/11] feat: eternal-ai on-chain system prompt --- Cargo.toml | 2 +- rig-core/Cargo.toml | 2 +- rig-core/src/providers/eternalai.rs | 74 +------------------ rig-eternalai/Cargo.toml | 10 +++ ...eternalai_system_prompt_manager_toolset.rs | 72 ++++++++++++++++++ rig-eternalai/src/lib.rs | 1 + 6 files changed, 87 insertions(+), 74 deletions(-) create mode 100644 rig-eternalai/Cargo.toml create mode 100644 rig-eternalai/src/eternalai_system_prompt_manager_toolset.rs create mode 100644 rig-eternalai/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index df48d1b..cb491be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,5 @@ members = [ "rig-core", "rig-lancedb", "rig-mongodb", "rig-neo4j", "rig-qdrant", "rig-core/rig-core-derive", - "rig-sqlite" + "rig-sqlite", "rig-eternalai", "rig-eternalai" ] diff --git a/rig-core/Cargo.toml b/rig-core/Cargo.toml index 202b56e..477ce65 100644 --- a/rig-core/Cargo.toml +++ b/rig-core/Cargo.toml @@ -24,11 +24,11 @@ ordered-float = "4.2.0" schemars = "0.8.16" thiserror = "1.0.61" rig-derive = { version = "0.1.0", path = "./rig-core-derive", optional = true } +rig-eternalai = { version = "0.1.0", path = "../rig-eternalai" } glob = "0.3.1" lopdf = { version = "0.34.0", optional = true } rayon = { version = "1.10.0", optional = true} worker = { version = "0.5", optional = true } -ethers = "2.0.14" [dev-dependencies] anyhow = "1.0.75" diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index 453bff1..f2bfe7f 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -16,22 +16,17 @@ use crate::{ extractor::ExtractorBuilder, json_utils, Embed, }; -use ethers::prelude::*; -use reqwest::get; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::ffi::c_uint; -use std::sync::Arc; use std::time::Duration; +use rig_eternalai::eternalai_system_prompt_manager_toolset; // ================================================================ // Main EternalAI Client // ================================================================ const ETERNALAI_API_BASE_URL: &str = "https://api.eternalai.org/v1"; -const IPFS: &str = "ipfs://"; -const LIGHTHOUSE_IPFS: &str = "https://gateway.lighthouse.storage/ipfs/"; -const GCS_ETERNAL_AI_BASE_URL: &str = "https://cdn.eternalai.org/upload/"; #[derive(Clone)] pub struct Client { base_url: String, @@ -337,71 +332,6 @@ pub fn get_chain_id(key: &str) -> Option<&str> { None } -pub async fn get_on_chain_system_prompt( - rpc_url: &str, - contract_addr: &str, - agent_id: c_uint, -) -> Result, String> { - abigen!( - SystemPromptManagementContract, - r#" - [{"inputs": [{"internalType": "uint256", "name": "_agentId", "type": "uint256"}], "name": "getAgentSystemPrompt", "outputs": [{"internalType": "bytes[]", "name": "","type": "bytes[]"}], "stateMutability": "view", "type": "function"}] - "# - ); - // Connect to an Ethereum node - let provider = - Provider::::try_from(rpc_url).map_err(|e| format!("Failed to parse url: {}", e))?; - let client = Arc::new(provider); - let contract_address: Address = contract_addr - .parse() - .map_err(|e| format!("invalid contract address: {}", e))?; - let contract = SystemPromptManagementContract::new(contract_address, client); - let system_prompts: Vec = contract - .get_agent_system_prompt(U256::from(agent_id)) - .call() - .await - .map_err(|e| format!("invalid agent system prompt: {}", e))?; - - let decoded_strings: Vec = system_prompts - .iter() - .map(|bytes| { - String::from_utf8(bytes.to_vec()).unwrap_or_else(|_| "[Invalid UTF-8]".to_string()) - }) - .collect(); - - if !decoded_strings.is_empty() { - let prompt = decoded_strings[0].clone(); - tracing::debug!("system prompt : {}", prompt); - return Ok(fetch_on_chain_or_ipfs_system_prompt(&prompt).await); - } - Ok(None) -} - -pub async fn fetch_on_chain_or_ipfs_system_prompt(content: &str) -> Option { - if content.contains(IPFS) { - let light_house = content.replace(IPFS, LIGHTHOUSE_IPFS); - tracing::debug!("light_house : {}", light_house); - let mut response = get(light_house).await.unwrap(); - if response.status().is_success() { - let body = response.text().await.unwrap(); - tracing::debug!("light_house body: {}", body); - return Some(body); - } else { - let gcs = content.replace(IPFS, GCS_ETERNAL_AI_BASE_URL); - tracing::debug!("gcs: {}", gcs); - response = get(gcs).await.unwrap(); - if response.status().is_success() { - let body = response.text().await.unwrap(); - tracing::debug!("gcs body: {}", body); - return Some(body); - } else { - return None; - } - } - } - Some(content.to_string()) -} - #[derive(Debug, Deserialize)] pub struct CompletionResponse { pub id: String, @@ -559,7 +489,7 @@ impl completion::CompletionModel for CompletionModel { ); let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); let prompt = - match get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value) + match eternalai_system_prompt_manager_toolset::get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value) .await { Ok(value) => value, diff --git a/rig-eternalai/Cargo.toml b/rig-eternalai/Cargo.toml new file mode 100644 index 0000000..de3ddb1 --- /dev/null +++ b/rig-eternalai/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rig-eternalai" +version = "0.1.0" +edition = "2021" + +[dependencies] +ethers = "2.0.14" +reqwest = "0.12.12" +tracing = "0.1.41" +tracing-subscriber = "0.3.19" diff --git a/rig-eternalai/src/eternalai_system_prompt_manager_toolset.rs b/rig-eternalai/src/eternalai_system_prompt_manager_toolset.rs new file mode 100644 index 0000000..921460f --- /dev/null +++ b/rig-eternalai/src/eternalai_system_prompt_manager_toolset.rs @@ -0,0 +1,72 @@ +use ethers::prelude::*; +use reqwest::get; +use std::ffi::c_uint; +use std::sync::Arc; + +const IPFS: &str = "ipfs://"; +const LIGHTHOUSE_IPFS: &str = "https://gateway.lighthouse.storage/ipfs/"; +const GCS_ETERNAL_AI_BASE_URL: &str = "https://cdn.eternalai.org/upload/"; + +pub async fn fetch_system_prompt_raw_or_ipfs(content: &str) -> Option { + if content.contains(IPFS) { + let light_house = content.replace(IPFS, LIGHTHOUSE_IPFS); + tracing::debug!("light_house : {}", light_house); + let mut response = get(light_house).await.unwrap(); + if response.status().is_success() { + let body = response.text().await.unwrap(); + tracing::debug!("light_house body: {}", body); + return Some(body); + } else { + let gcs = content.replace(IPFS, GCS_ETERNAL_AI_BASE_URL); + tracing::debug!("gcs: {}", gcs); + response = get(gcs).await.unwrap(); + if response.status().is_success() { + let body = response.text().await.unwrap(); + tracing::debug!("gcs body: {}", body); + return Some(body); + } else { + return None; + } + } + } + Some(content.to_string()) +} + +pub async fn get_on_chain_system_prompt( + rpc_url: &str, + contract_addr: &str, + agent_id: c_uint, +) -> Result, String> { + abigen!( + SystemPromptManagementContract, + r#" + [{"inputs": [{"internalType": "uint256", "name": "_agentId", "type": "uint256"}], "name": "getAgentSystemPrompt", "outputs": [{"internalType": "bytes[]", "name": "","type": "bytes[]"}], "stateMutability": "view", "type": "function"}] + "# + ); + let provider = + Provider::::try_from(rpc_url).map_err(|e| format!("Failed to parse url: {}", e))?; + let client = Arc::new(provider); + let contract_address: Address = contract_addr + .parse() + .map_err(|e| format!("invalid contract address: {}", e))?; + let contract = SystemPromptManagementContract::new(contract_address, client); + let system_prompts: Vec = contract + .get_agent_system_prompt(U256::from(agent_id)) + .call() + .await + .map_err(|e| format!("invalid agent system prompt: {}", e))?; + + let decoded_strings: Vec = system_prompts + .iter() + .map(|bytes| { + String::from_utf8(bytes.to_vec()).unwrap_or_else(|_| "[Invalid UTF-8]".to_string()) + }) + .collect(); + + if !decoded_strings.is_empty() { + let prompt = decoded_strings[0].clone(); + tracing::debug!("system prompt : {}", prompt); + return Ok(fetch_system_prompt_raw_or_ipfs(&prompt).await); + } + Ok(None) +} diff --git a/rig-eternalai/src/lib.rs b/rig-eternalai/src/lib.rs new file mode 100644 index 0000000..94deab3 --- /dev/null +++ b/rig-eternalai/src/lib.rs @@ -0,0 +1 @@ +pub mod eternalai_system_prompt_manager_toolset; \ No newline at end of file From b49c03c225df7e212f0d3abd63fff519472599da Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 11:26:28 +0700 Subject: [PATCH 08/11] feat: eternal-ai on-chain system prompt --- rig-core/src/providers/eternalai.rs | 19 +++++++++++-------- rig-eternalai/src/lib.rs | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rig-core/src/providers/eternalai.rs b/rig-core/src/providers/eternalai.rs index f2bfe7f..f17dfc2 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-core/src/providers/eternalai.rs @@ -16,12 +16,12 @@ use crate::{ extractor::ExtractorBuilder, json_utils, Embed, }; +use rig_eternalai::eternalai_system_prompt_manager_toolset; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use std::ffi::c_uint; use std::time::Duration; -use rig_eternalai::eternalai_system_prompt_manager_toolset; // ================================================================ // Main EternalAI Client @@ -488,13 +488,16 @@ impl completion::CompletionModel for CompletionModel { eternal_ai_agent_id ); let c_value: c_uint = eternal_ai_agent_id.parse::().unwrap_or(0); - let prompt = - match eternalai_system_prompt_manager_toolset::get_on_chain_system_prompt(&eternal_ai_rpc, &eternal_ai_contract, c_value) - .await - { - Ok(value) => value, - Err(e) => return Err(CompletionError::ProviderError(e)), - }; + let prompt = match eternalai_system_prompt_manager_toolset::get_on_chain_system_prompt( + &eternal_ai_rpc, + &eternal_ai_contract, + c_value, + ) + .await + { + Ok(value) => value, + Err(e) => return Err(CompletionError::ProviderError(e)), + }; match prompt { None => { tracing::info!("on-chain sytem prompt is none") diff --git a/rig-eternalai/src/lib.rs b/rig-eternalai/src/lib.rs index 94deab3..0727b32 100644 --- a/rig-eternalai/src/lib.rs +++ b/rig-eternalai/src/lib.rs @@ -1 +1 @@ -pub mod eternalai_system_prompt_manager_toolset; \ No newline at end of file +pub mod eternalai_system_prompt_manager_toolset; From a6a67c3c9686853f1d20a3bfc1cd82ffb3598726 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 11:27:44 +0700 Subject: [PATCH 09/11] feat: eternal-ai on-chain system prompt --- rig-eternalai/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rig-eternalai/Cargo.toml b/rig-eternalai/Cargo.toml index de3ddb1..801850f 100644 --- a/rig-eternalai/Cargo.toml +++ b/rig-eternalai/Cargo.toml @@ -7,4 +7,3 @@ edition = "2021" ethers = "2.0.14" reqwest = "0.12.12" tracing = "0.1.41" -tracing-subscriber = "0.3.19" From 5ae0b2213787738e53d2f97c3ef90d75bf777211 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 11:32:35 +0700 Subject: [PATCH 10/11] feat: eternal-ai on-chain system prompt --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cb491be..6937f36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,5 @@ members = [ "rig-core", "rig-lancedb", "rig-mongodb", "rig-neo4j", "rig-qdrant", "rig-core/rig-core-derive", - "rig-sqlite", "rig-eternalai", "rig-eternalai" + "rig-sqlite", "rig-eternalai" ] From dfdbc23b0cac5a50acb8d565f58049fa40f876f4 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 17 Jan 2025 11:33:13 +0700 Subject: [PATCH 11/11] feat: eternal-ai on-chain system prompt --- rig-core/examples/agent_with_eternalai.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rig-core/examples/agent_with_eternalai.rs b/rig-core/examples/agent_with_eternalai.rs index 83fa1a8..3a028d4 100644 --- a/rig-core/examples/agent_with_eternalai.rs +++ b/rig-core/examples/agent_with_eternalai.rs @@ -5,7 +5,7 @@ use rig::{completion::Prompt, providers}; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) // Đặt mức độ tối đa là DEBUG + .with_max_level(tracing::Level::DEBUG) .init(); println!("Running basic agent with eternalai"); basic_eternalai().await?;