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

feat(model): add support for EternalAI onchain toolset #205

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions rig-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
103 changes: 102 additions & 1 deletion rig-core/src/providers/eternalai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +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;

// ================================================================
// 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,
Expand Down Expand Up @@ -331,6 +337,68 @@ 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,
) -> Option<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::<Http>::try_from(rpc_url).expect("Failed to parse url");
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
let client = Arc::new(provider);
let contract_address: Address = contract_addr.parse().expect("invalid contract address");
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
let contract = SystemPromptManagementContract::new(contract_address, client);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to store all those values in some sort of OnChainClient struct so we don't have to initialize them every time the function is called

let system_prompts: Vec<Bytes> = contract
.get_agent_system_prompt(U256::from(agent_id))
.call()
.await
.expect("invalid agent system prompt");
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved

let decoded_strings: Vec<String> = 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();
println!("system prompt : {}", prompt);
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
return fetch_on_chain_system_prompt(&prompt).await;
}
None
}

pub async fn fetch_on_chain_system_prompt(content: &str) -> Option<String> {
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
if content.contains(IPFS) {
let light_house = content.replace(IPFS, LIGHTHOUSE_IPFS);
println!("light_house : {}", light_house);
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
let mut response = get(light_house).await.unwrap();
if response.status().is_success() {
let body = response.text().await.unwrap();
println!("light_house body: {}", body);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use tracing macros

return Some(body);
} else {
let gcs = content.replace(IPFS, GCS_ETERNAL_AI_BASE_URL);
println!("gcs: {}", gcs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use tracing macros

response = get(gcs).await.unwrap();
if response.status().is_success() {
let body = response.text().await.unwrap();
println!("gcs body: {}", body);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use tracing macros

return Some(body);
} else {
return None;
}
}
}
Some(content.to_string())
}

#[derive(Debug, Deserialize)]
pub struct CompletionResponse {
pub id: String,
Expand Down Expand Up @@ -470,6 +538,37 @@ impl completion::CompletionModel for CompletionModel {
vec![]
};

println!("Try to get on-chain system prompt");
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
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
);
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
let c_value: c_uint = eternal_ai_agent_id.parse::<u32>().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")
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved
}
Some(value) => {
let temp = completion::Message {
role: "system".into(),
content: value,
};
full_history.push(temp);
}
}
}

// Extend existing chat history
full_history.append(&mut completion_request.chat_history);

Expand Down Expand Up @@ -505,6 +604,8 @@ impl completion::CompletionModel for CompletionModel {
})
};

println!("request: {:?}", request.to_string());
eternal-ai-org marked this conversation as resolved.
Show resolved Hide resolved

let response = self
.client
.post("/chat/completions")
Expand Down
Loading