From 431b69e261b9cf9179f30bc62166708de5b2e998 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Wed, 15 Jan 2025 16:19:49 +0700 Subject: [PATCH 01/15] 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 1afd7c05..202b56e0 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 fc91b28c..b0da7bde 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/15] 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 b0da7bde..abe0759e 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/15] 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 abe0759e..7c6b10f9 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/15] 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 7c6b10f9..86362547 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/15] 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 86362547..0af6e23d 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/15] 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 56bd45d3..83fa1a84 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 0af6e23d..453bff11 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/15] 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 df48d1b3..cb491bef 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 202b56e0..477ce653 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 453bff11..f2bfe7f4 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 00000000..de3ddb16 --- /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 00000000..921460f0 --- /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 00000000..94deab32 --- /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/15] 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 f2bfe7f4..f17dfc2b 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 94deab32..0727b32f 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/15] 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 de3ddb16..801850f1 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/15] 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 cb491bef..6937f367 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/15] 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 83fa1a84..3a028d48 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?; From d70b3e1ce1b9047603a3a325cf987de7f438b5eb Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Tue, 21 Jan 2025 15:17:32 +0700 Subject: [PATCH 12/15] feat: eternal-ai on-chain system prompt --- rig-core/Cargo.toml | 1 - rig-core/src/completion.rs | 2 +- rig-core/src/providers/mod.rs | 1 - rig-eternalai/Cargo.toml | 13 +++++++-- .../examples/agent_with_eternalai.rs | 12 +++++---- rig-eternalai/src/lib.rs | 5 ++++ .../src/providers/eternalai.rs | 27 +++++++++---------- rig-eternalai/src/providers/mod.rs | 1 + 8 files changed, 38 insertions(+), 24 deletions(-) rename {rig-core => rig-eternalai}/examples/agent_with_eternalai.rs (86%) rename {rig-core => rig-eternalai}/src/providers/eternalai.rs (96%) create mode 100644 rig-eternalai/src/providers/mod.rs diff --git a/rig-core/Cargo.toml b/rig-core/Cargo.toml index 477ce653..1afd7c05 100644 --- a/rig-core/Cargo.toml +++ b/rig-core/Cargo.toml @@ -24,7 +24,6 @@ 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} diff --git a/rig-core/src/completion.rs b/rig-core/src/completion.rs index f13f316b..610c7f00 100644 --- a/rig-core/src/completion.rs +++ b/rig-core/src/completion.rs @@ -266,7 +266,7 @@ pub struct CompletionRequest { } impl CompletionRequest { - pub(crate) fn prompt_with_context(&self) -> String { + pub fn prompt_with_context(&self) -> String { if !self.documents.is_empty() { format!( "\n{}\n\n{}", diff --git a/rig-core/src/providers/mod.rs b/rig-core/src/providers/mod.rs index f5c3bce7..f52a0b41 100644 --- a/rig-core/src/providers/mod.rs +++ b/rig-core/src/providers/mod.rs @@ -44,7 +44,6 @@ //! be used with the Cohere provider client. pub mod anthropic; pub mod cohere; -pub mod eternalai; pub mod gemini; pub mod openai; pub mod perplexity; diff --git a/rig-eternalai/Cargo.toml b/rig-eternalai/Cargo.toml index 801850f1..995f0552 100644 --- a/rig-eternalai/Cargo.toml +++ b/rig-eternalai/Cargo.toml @@ -4,6 +4,15 @@ version = "0.1.0" edition = "2021" [dependencies] +rig-core = { path = "../rig-core", version = "0.6.1" } ethers = "2.0.14" -reqwest = "0.12.12" -tracing = "0.1.41" +reqwest = { version = "0.11.22", features = ["json"] } +serde = { version = "1.0.193", features = ["derive"] } +serde_json = "1.0.108" +tracing = "0.1.40" +schemars = "0.8.16" + +[dev-dependencies] +anyhow = "1.0.75" +tokio = { version = "1.34.0", features = ["full"] } +tracing-subscriber = "0.3.18" \ No newline at end of file diff --git a/rig-core/examples/agent_with_eternalai.rs b/rig-eternalai/examples/agent_with_eternalai.rs similarity index 86% rename from rig-core/examples/agent_with_eternalai.rs rename to rig-eternalai/examples/agent_with_eternalai.rs index 3a028d48..7b4ffe79 100644 --- a/rig-core/examples/agent_with_eternalai.rs +++ b/rig-eternalai/examples/agent_with_eternalai.rs @@ -1,6 +1,8 @@ use rig::agent::AgentBuilder; -use rig::providers::eternalai::{CompletionModel, NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8}; -use rig::{completion::Prompt, providers}; +use rig::completion::Prompt; +use rig_eternalai::providers::eternalai::{ + Client, CompletionModel, NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8, +}; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { @@ -17,8 +19,8 @@ async fn main() -> Result<(), anyhow::Error> { Ok(()) } -fn client() -> providers::eternalai::Client { - providers::eternalai::Client::from_env() +fn client() -> Client { + Client::from_env() } fn partial_agent_eternalai() -> AgentBuilder { @@ -44,7 +46,7 @@ async fn basic_eternalai() -> Result<(), anyhow::Error> { async fn context_eternalai() -> Result<(), anyhow::Error> { let model = client().completion_model( - providers::eternalai::NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8, + NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8, Option::from("45762"), // None, ); diff --git a/rig-eternalai/src/lib.rs b/rig-eternalai/src/lib.rs index 0727b32f..c0754f64 100644 --- a/rig-eternalai/src/lib.rs +++ b/rig-eternalai/src/lib.rs @@ -1 +1,6 @@ pub mod eternalai_system_prompt_manager_toolset; +pub mod providers; + +pub mod json_utils; +// pub mod completion; + diff --git a/rig-core/src/providers/eternalai.rs b/rig-eternalai/src/providers/eternalai.rs similarity index 96% rename from rig-core/src/providers/eternalai.rs rename to rig-eternalai/src/providers/eternalai.rs index f17dfc2b..83e4e861 100644 --- a/rig-core/src/providers/eternalai.rs +++ b/rig-eternalai/src/providers/eternalai.rs @@ -2,21 +2,20 @@ //! //! # Example //! ``` -//! use rig::providers::eternalai; +//! use rig_eternalai::providers::eternalai; //! //! let client = eternalai::Client::new("YOUR_API_KEY"); //! //! let gpt4o = client.completion_model(eternalai::NOUS_RESEARCH_HERMES_3_LLAMA_3_1_70B_FP8); //! ``` -use crate::{ - agent::AgentBuilder, - completion::{self, CompletionError, CompletionRequest}, - embeddings::{self, EmbeddingError, EmbeddingsBuilder}, - extractor::ExtractorBuilder, - json_utils, Embed, -}; -use rig_eternalai::eternalai_system_prompt_manager_toolset; +use crate::eternalai_system_prompt_manager_toolset; +use crate::json_utils; +use rig::agent::AgentBuilder; +use rig::completion::{CompletionError, CompletionRequest}; +use rig::embeddings::{EmbeddingError, EmbeddingsBuilder}; +use rig::extractor::ExtractorBuilder; +use rig::{completion, embeddings, Embed}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; @@ -78,7 +77,7 @@ impl Client { /// /// # Example /// ``` - /// use rig::providers::eternalai::{Client, self}; + /// use rig_eternalai::providers::eternalai::{Client, self}; /// /// // Initialize the EternalAI client /// let eternalai = Client::new("your-open-ai-api-key"); @@ -98,7 +97,7 @@ impl Client { /// /// # Example /// ``` - /// use rig::providers::eternalai::{Client, self}; + /// use rig_eternalai::providers::eternalai::{Client, self}; /// /// // Initialize the EternalAI client /// let eternalai = Client::new("your-open-ai-api-key"); @@ -113,7 +112,7 @@ impl Client { /// /// # Example /// ``` - /// use rig::providers::eternalai::{Client, self}; + /// use rig_eternalai::providers::eternalai::{Client, self}; /// /// // Initialize the EternalAI client /// let eternalai = Client::new("your-open-ai-api-key"); @@ -133,7 +132,7 @@ impl Client { /// /// # Example /// ``` - /// use rig::providers::eternalai::{Client, self}; + /// use rig_eternalai::providers::eternalai::{Client, self}; /// /// // Initialize the EternalAI client /// let eternalai = Client::new("your-open-ai-api-key"); @@ -148,7 +147,7 @@ impl Client { /// /// # Example /// ``` - /// use rig::providers::eternalai::{Client, self}; + /// use rig_eternalai::providers::eternalai::{Client, self}; /// /// // Initialize the Eternal client /// let eternalai = Client::new("your-open-ai-api-key"); diff --git a/rig-eternalai/src/providers/mod.rs b/rig-eternalai/src/providers/mod.rs new file mode 100644 index 00000000..d42dffe8 --- /dev/null +++ b/rig-eternalai/src/providers/mod.rs @@ -0,0 +1 @@ +pub mod eternalai; From 02a03ac17ece197cae94166762b27130fc762e11 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Tue, 21 Jan 2025 15:21:04 +0700 Subject: [PATCH 13/15] feat: eternal-ai on-chain system prompt --- rig-eternalai/src/json_utils.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 rig-eternalai/src/json_utils.rs diff --git a/rig-eternalai/src/json_utils.rs b/rig-eternalai/src/json_utils.rs new file mode 100644 index 00000000..25d3ef91 --- /dev/null +++ b/rig-eternalai/src/json_utils.rs @@ -0,0 +1,19 @@ +pub fn merge(a: serde_json::Value, b: serde_json::Value) -> serde_json::Value { + match (a, b) { + (serde_json::Value::Object(mut a_map), serde_json::Value::Object(b_map)) => { + b_map.into_iter().for_each(|(key, value)| { + a_map.insert(key, value); + }); + serde_json::Value::Object(a_map) + } + (a, _) => a, + } +} + +pub fn merge_inplace(a: &mut serde_json::Value, b: serde_json::Value) { + if let (serde_json::Value::Object(a_map), serde_json::Value::Object(b_map)) = (a, b) { + b_map.into_iter().for_each(|(key, value)| { + a_map.insert(key, value); + }); + } +} From 6410b4c70a61a6b02bbae4d32d9cddb6e4dfd85e Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Tue, 21 Jan 2025 15:25:41 +0700 Subject: [PATCH 14/15] feat: eternal-ai on-chain system prompt --- rig-eternalai/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rig-eternalai/src/lib.rs b/rig-eternalai/src/lib.rs index c0754f64..d3989834 100644 --- a/rig-eternalai/src/lib.rs +++ b/rig-eternalai/src/lib.rs @@ -3,4 +3,3 @@ pub mod providers; pub mod json_utils; // pub mod completion; - From 83e4440ac292c779d1063dfb1157b05467fb8105 Mon Sep 17 00:00:00 2001 From: genesis0000 Date: Fri, 24 Jan 2025 03:53:35 +0700 Subject: [PATCH 15/15] feat: eternal-ai on-chain system prompt --- rig-eternalai/src/providers/eternalai.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rig-eternalai/src/providers/eternalai.rs b/rig-eternalai/src/providers/eternalai.rs index e5d50a1f..d26f276a 100644 --- a/rig-eternalai/src/providers/eternalai.rs +++ b/rig-eternalai/src/providers/eternalai.rs @@ -471,7 +471,7 @@ impl completion::CompletionModel for CompletionModel { vec![] }; - println!("Try to get on-chain system prompt"); + tracing::info!("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());