mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-19 06:31:30 +03:00
Merge pull request #58 from uqbar-dao/da/runtime-extensions
Da/runtime extensions
This commit is contained in:
commit
a744112402
96
Cargo.lock
generated
96
Cargo.lock
generated
@ -138,6 +138,54 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
@ -630,6 +678,33 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "coins-bip32"
|
||||
version = "0.8.7"
|
||||
@ -682,6 +757,12 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "const-hex"
|
||||
version = "1.8.0"
|
||||
@ -1037,7 +1118,7 @@ dependencies = [
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"strsim 0.9.3",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@ -4421,6 +4502,12 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.25.0"
|
||||
@ -5007,6 +5094,7 @@ dependencies = [
|
||||
"cap-std",
|
||||
"chacha20poly1305 0.10.1",
|
||||
"chrono",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"dashmap",
|
||||
"digest 0.10.7",
|
||||
@ -5084,6 +5172,12 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
|
@ -68,3 +68,7 @@ warp = "0.3.5"
|
||||
wasmtime = "14.0.4"
|
||||
wasmtime-wasi = "14.0.4"
|
||||
zip = "0.6"
|
||||
clap = "4.4.8"
|
||||
|
||||
[features]
|
||||
llm = []
|
||||
|
@ -16,6 +16,7 @@ pub async fn load_fs(
|
||||
home_directory_path: String,
|
||||
file_key: Vec<u8>,
|
||||
fs_config: FsConfig,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
) -> Result<(ProcessMap, Manifest, Vec<KernelMessage>), FsError> {
|
||||
// load/create fs directory, manifest + log if none.
|
||||
let fs_directory_path_str = format!("{}/fs", &home_directory_path);
|
||||
@ -71,6 +72,7 @@ pub async fn load_fs(
|
||||
bootstrap(
|
||||
&our_name,
|
||||
&kernel_process_id,
|
||||
runtime_extensions,
|
||||
&mut process_map,
|
||||
&mut manifest,
|
||||
)
|
||||
@ -97,27 +99,34 @@ pub async fn load_fs(
|
||||
async fn bootstrap(
|
||||
our_name: &str,
|
||||
kernel_process_id: &FileIdentifier,
|
||||
runtime_extensions: Vec<(ProcessId, MessageSender, bool)>,
|
||||
process_map: &mut ProcessMap,
|
||||
manifest: &mut Manifest,
|
||||
) -> Result<Vec<KernelMessage>> {
|
||||
println!("bootstrapping node...\r");
|
||||
const RUNTIME_MODULES: [(&str, bool); 8] = [
|
||||
("filesystem:sys:uqbar", false),
|
||||
("http_server:sys:uqbar", true), // TODO evaluate
|
||||
("http_client:sys:uqbar", false),
|
||||
("encryptor:sys:uqbar", false),
|
||||
("net:sys:uqbar", false),
|
||||
("vfs:sys:uqbar", true),
|
||||
("kernel:sys:uqbar", false),
|
||||
("eth_rpc:sys:uqbar", true), // TODO evaluate
|
||||
];
|
||||
|
||||
let mut runtime_caps: HashSet<Capability> = HashSet::new();
|
||||
for runtime_module in RUNTIME_MODULES {
|
||||
// kernel is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str(runtime_module.0).unwrap(),
|
||||
process: ProcessId::from_str("kernel:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
// net is a special case
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: ProcessId::from_str("net:sys:uqbar").unwrap(),
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
for runtime_module in runtime_extensions.clone() {
|
||||
runtime_caps.insert(Capability {
|
||||
issuer: Address {
|
||||
node: our_name.to_string(),
|
||||
process: runtime_module.0,
|
||||
},
|
||||
params: "\"messaging\"".into(),
|
||||
});
|
||||
@ -132,14 +141,31 @@ async fn bootstrap(
|
||||
});
|
||||
|
||||
// finally, save runtime modules in state map as well, somewhat fakely
|
||||
for runtime_module in RUNTIME_MODULES {
|
||||
// special cases for kernel and net
|
||||
process_map
|
||||
.entry(ProcessId::from_str(runtime_module.0).unwrap())
|
||||
.entry(ProcessId::from_str("kernel:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: runtime_module.1,
|
||||
public: false,
|
||||
});
|
||||
process_map
|
||||
.entry(ProcessId::from_str("net:sys:uqbar").unwrap())
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: false,
|
||||
});
|
||||
for runtime_module in runtime_extensions {
|
||||
process_map
|
||||
.entry(runtime_module.0)
|
||||
.or_insert(PersistedProcess {
|
||||
wasm_bytes_handle: 0,
|
||||
on_panic: OnPanic::Restart,
|
||||
capabilities: runtime_caps.clone(),
|
||||
public: runtime_module.2,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1802,48 +1802,22 @@ async fn make_event_loop(
|
||||
mut recv_debug_in_loop: t::DebugReceiver,
|
||||
send_to_loop: t::MessageSender,
|
||||
send_to_net: t::MessageSender,
|
||||
send_to_fs: t::MessageSender,
|
||||
send_to_http_server: t::MessageSender,
|
||||
send_to_http_client: t::MessageSender,
|
||||
send_to_eth_rpc: t::MessageSender,
|
||||
send_to_vfs: t::MessageSender,
|
||||
send_to_encryptor: t::MessageSender,
|
||||
send_to_terminal: t::PrintSender,
|
||||
engine: Engine,
|
||||
runtime_extensions: Vec<(t::ProcessId, t::MessageSender, bool)>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<()>> + Send>> {
|
||||
// shared global flag to mark if we're finished boot process
|
||||
let booted = Arc::new(AtomicBool::new(false));
|
||||
|
||||
Box::pin(async move {
|
||||
let mut senders: Senders = HashMap::new();
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("eth_rpc"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_eth_rpc),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("filesystem"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_fs),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("http_server"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_http_server),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("http_client"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_http_client),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("encryptor"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_encryptor),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("net"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_net.clone()),
|
||||
);
|
||||
senders.insert(
|
||||
t::ProcessId::new(Some("vfs"), "sys", "uqbar"),
|
||||
ProcessSender::Runtime(send_to_vfs),
|
||||
);
|
||||
for (process_id, sender, _) in runtime_extensions {
|
||||
senders.insert(process_id, ProcessSender::Runtime(sender));
|
||||
}
|
||||
|
||||
// each running process is stored in this map
|
||||
let mut process_handles: ProcessHandles = HashMap::new();
|
||||
@ -2235,12 +2209,7 @@ pub async fn kernel(
|
||||
network_error_recv: t::NetworkErrorReceiver,
|
||||
recv_debug_in_loop: t::DebugReceiver,
|
||||
send_to_wss: t::MessageSender,
|
||||
send_to_fs: t::MessageSender,
|
||||
send_to_http_server: t::MessageSender,
|
||||
send_to_http_client: t::MessageSender,
|
||||
send_to_eth_rpc: t::MessageSender,
|
||||
send_to_vfs: t::MessageSender,
|
||||
send_to_encryptor: t::MessageSender,
|
||||
runtime_extensions: Vec<(t::ProcessId, t::MessageSender, bool)>,
|
||||
) -> Result<()> {
|
||||
let mut config = Config::new();
|
||||
config.cache_config_load_default().unwrap();
|
||||
@ -2261,14 +2230,9 @@ pub async fn kernel(
|
||||
recv_debug_in_loop,
|
||||
send_to_loop,
|
||||
send_to_wss,
|
||||
send_to_fs,
|
||||
send_to_http_server,
|
||||
send_to_http_client,
|
||||
send_to_eth_rpc,
|
||||
send_to_vfs,
|
||||
send_to_encryptor,
|
||||
send_to_terminal,
|
||||
engine,
|
||||
runtime_extensions,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
7
src/llm/README.md
Normal file
7
src/llm/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Local LLM Integration
|
||||
1. Clone and build [llama.cpp](https://github.com/ggerganov/llama.cpp) on the same machine where you will run your uqbar node
|
||||
- follow their README for details on how to do this. In most cases simply running `make` works
|
||||
- make sure to get your model as a .gguf file
|
||||
2. Within the llama.cpp directory, run this command in llama.cpp on the same machine you will run your uqbar node: `./server --port <PORT>`
|
||||
- Note: you can pass in whatever other command line arguments to the llama cpp server you want depending on your preferences/hardware/model/etc.
|
||||
3. Run your Uqbar node with `--features llm` and `--llm http://localhost:<PORT>`. For example `cargo +nightly run --features llm --release home --rpc wss://eth-sepolia.g.alchemy.com/v2/<YOUR_API_KEY> --llm http://localhost:<PORT>`
|
180
src/llm/mod.rs
Normal file
180
src/llm/mod.rs
Normal file
@ -0,0 +1,180 @@
|
||||
use crate::llm::types::*;
|
||||
use crate::types::*;
|
||||
use anyhow::Result;
|
||||
use reqwest::Response as ReqwestResponse;
|
||||
|
||||
mod types;
|
||||
|
||||
pub async fn llm(
|
||||
our_name: String,
|
||||
send_to_loop: MessageSender,
|
||||
mut recv_in_client: MessageReceiver,
|
||||
llm_url: String,
|
||||
print_tx: PrintSender,
|
||||
) -> Result<()> {
|
||||
while let Some(message) = recv_in_client.recv().await {
|
||||
let KernelMessage {
|
||||
id,
|
||||
source,
|
||||
rsvp,
|
||||
message:
|
||||
Message::Request(Request {
|
||||
expects_response,
|
||||
ipc,
|
||||
..
|
||||
}),
|
||||
..
|
||||
} = message.clone()
|
||||
else {
|
||||
return Err(anyhow::anyhow!("llm: bad message"));
|
||||
};
|
||||
|
||||
let our_name = our_name.clone();
|
||||
let llm_url = llm_url.clone();
|
||||
let send_to_loop = send_to_loop.clone();
|
||||
let print_tx = print_tx.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = handle_message(
|
||||
our_name.clone(),
|
||||
send_to_loop.clone(),
|
||||
llm_url.clone(),
|
||||
id,
|
||||
rsvp,
|
||||
expects_response,
|
||||
source.clone(),
|
||||
ipc,
|
||||
print_tx.clone(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
send_to_loop
|
||||
.send(make_error_message(our_name.clone(), id, source, e))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
Err(anyhow::anyhow!("llm: exited"))
|
||||
}
|
||||
|
||||
async fn handle_message(
|
||||
our: String,
|
||||
send_to_loop: MessageSender,
|
||||
llm_url: String,
|
||||
id: u64,
|
||||
rsvp: Option<Address>,
|
||||
expects_response: Option<u64>,
|
||||
source: Address,
|
||||
json: Vec<u8>,
|
||||
_print_tx: PrintSender,
|
||||
) -> Result<(), LlmError> {
|
||||
let target = if expects_response.is_some() {
|
||||
source.clone()
|
||||
} else if source.process == ProcessId::from_str("terminal:terminal:uqbar").unwrap() {
|
||||
source.clone()
|
||||
} else {
|
||||
let Some(rsvp) = rsvp else {
|
||||
return Err(LlmError::BadRsvp);
|
||||
};
|
||||
rsvp.clone()
|
||||
};
|
||||
|
||||
let req: LlmPrompt = match serde_json::from_slice(&json) {
|
||||
Ok(req) => req,
|
||||
Err(e) => {
|
||||
return Err(LlmError::BadJson {
|
||||
json: String::from_utf8(json).unwrap_or_default(),
|
||||
error: format!("{}", e),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let res: ReqwestResponse = match client
|
||||
.post(&format!("{}/completion", llm_url))
|
||||
.json(&req)
|
||||
.send()
|
||||
.await
|
||||
{
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
return Err(LlmError::RequestFailed {
|
||||
error: format!("{}", e),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let llm_response = match res.json::<LlmResponse>().await {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
return Err(LlmError::DeserializationToLlmResponseFailed {
|
||||
error: format!("{}", e),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let _ = _print_tx
|
||||
.send(Printout {
|
||||
verbosity: 0,
|
||||
content: format!("llm: {:?}", llm_response.clone().content),
|
||||
})
|
||||
.await;
|
||||
|
||||
let message = KernelMessage {
|
||||
id,
|
||||
source: Address {
|
||||
node: our,
|
||||
process: ProcessId::new(Some("llm"), "sys", "uqbar"),
|
||||
},
|
||||
target,
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<LlmResponse, LlmError>>(&Ok(llm_response))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
};
|
||||
|
||||
send_to_loop.send(message).await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//
|
||||
// helpers
|
||||
//
|
||||
fn make_error_message(
|
||||
our_name: String,
|
||||
id: u64,
|
||||
source: Address,
|
||||
error: LlmError,
|
||||
) -> KernelMessage {
|
||||
KernelMessage {
|
||||
id,
|
||||
source: source.clone(),
|
||||
target: Address {
|
||||
node: our_name.clone(),
|
||||
process: source.process.clone(),
|
||||
},
|
||||
rsvp: None,
|
||||
message: Message::Response((
|
||||
Response {
|
||||
inherit: false,
|
||||
ipc: serde_json::to_vec::<Result<HttpClientResponse, LlmError>>(&Err(error))
|
||||
.unwrap(),
|
||||
metadata: None,
|
||||
},
|
||||
None,
|
||||
)),
|
||||
payload: None,
|
||||
signed_capabilities: None,
|
||||
}
|
||||
}
|
114
src/llm/types.rs
Normal file
114
src/llm/types.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LlmPrompt {
|
||||
prompt: String, // TODO can be a string or an array of strings
|
||||
temperature: Option<f64>,
|
||||
top_k: Option<usize>,
|
||||
top_p: Option<f64>,
|
||||
n_predict: Option<isize>, // isize to accommodate -1
|
||||
n_keep: Option<isize>, // isize to accommodate -1
|
||||
stream: Option<bool>,
|
||||
stop: Option<Vec<String>>,
|
||||
tfs_z: Option<f64>,
|
||||
typical_p: Option<f64>,
|
||||
repeat_penalty: Option<f64>,
|
||||
repeat_last_n: Option<isize>, // isize to accommodate -1
|
||||
penalize_nl: Option<bool>,
|
||||
presence_penalty: Option<f64>,
|
||||
frequency_penalty: Option<f64>,
|
||||
mirostat: Option<u8>, // u8 as it's 0, 1, or 2
|
||||
mirostat_tau: Option<f64>,
|
||||
mirostat_eta: Option<f64>,
|
||||
grammar: Option<String>,
|
||||
seed: Option<isize>, // isize to accommodate -1
|
||||
ignore_eos: Option<bool>,
|
||||
logit_bias: Option<Vec<(usize, f64)>>,
|
||||
n_probs: Option<usize>,
|
||||
image_data: Option<Vec<ImageData>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ImageData {
|
||||
data: String, // Base64 string
|
||||
id: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct LlmResponse {
|
||||
pub content: String,
|
||||
pub generation_settings: GenerationSettings,
|
||||
pub model: String,
|
||||
pub prompt: String,
|
||||
pub slot_id: u64,
|
||||
pub stop: bool,
|
||||
pub stopped_eos: bool,
|
||||
pub stopped_limit: bool,
|
||||
pub stopped_word: bool,
|
||||
pub stopping_word: String,
|
||||
pub timings: Timings,
|
||||
pub tokens_cached: u64,
|
||||
pub tokens_evaluated: u64,
|
||||
pub tokens_predicted: u64,
|
||||
pub truncated: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct GenerationSettings {
|
||||
pub frequency_penalty: f64,
|
||||
pub grammar: String,
|
||||
pub ignore_eos: bool,
|
||||
pub logit_bias: Vec<serde_json::Value>, // This should be changed to the appropriate type
|
||||
pub mirostat: u64,
|
||||
pub mirostat_eta: f64,
|
||||
pub mirostat_tau: f64,
|
||||
pub model: String,
|
||||
pub n_ctx: u64,
|
||||
pub n_keep: u64,
|
||||
pub n_predict: u64,
|
||||
pub n_probs: u64,
|
||||
pub penalize_nl: bool,
|
||||
pub presence_penalty: f64,
|
||||
pub repeat_last_n: u64,
|
||||
pub repeat_penalty: f64,
|
||||
pub seed: u64,
|
||||
pub stop: Vec<serde_json::Value>, // This should be changed to the appropriate type
|
||||
pub stream: bool,
|
||||
pub temp: f64,
|
||||
pub tfs_z: f64,
|
||||
pub top_k: u64,
|
||||
pub top_p: f64,
|
||||
pub typical_p: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct Timings {
|
||||
pub predicted_ms: f64,
|
||||
pub predicted_n: u64,
|
||||
pub predicted_per_second: f64,
|
||||
pub predicted_per_token_ms: f64,
|
||||
pub prompt_ms: f64,
|
||||
pub prompt_n: u64,
|
||||
pub prompt_per_second: f64,
|
||||
pub prompt_per_token_ms: f64,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug, Serialize, Deserialize)]
|
||||
pub enum LlmError {
|
||||
#[error("llm: rsvp is None but message is expecting response")]
|
||||
BadRsvp,
|
||||
#[error("llm: no json in request")]
|
||||
NoJson,
|
||||
#[error(
|
||||
"llm: JSON payload could not be parsed to LlmPrompt: {error}. Got {:?}.",
|
||||
json
|
||||
)]
|
||||
BadJson { json: String, error: String },
|
||||
#[error("llm: http method not supported: {:?}", method)]
|
||||
BadMethod { method: String },
|
||||
#[error("llm: failed to execute request {:?}", error)]
|
||||
RequestFailed { error: String },
|
||||
#[error("llm: failed to deserialize response {:?}", error)]
|
||||
DeserializationToLlmResponseFailed { error: String },
|
||||
}
|
109
src/main.rs
109
src/main.rs
@ -1,6 +1,6 @@
|
||||
use crate::types::*;
|
||||
use anyhow::Result;
|
||||
|
||||
use clap::{arg, Command};
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
@ -19,6 +19,10 @@ mod terminal;
|
||||
mod types;
|
||||
mod vfs;
|
||||
|
||||
// extensions
|
||||
#[cfg(feature = "llm")]
|
||||
mod llm;
|
||||
|
||||
const EVENT_LOOP_CHANNEL_CAPACITY: usize = 10_000;
|
||||
const EVENT_LOOP_DEBUG_CHANNEL_CAPACITY: usize = 50;
|
||||
const TERMINAL_CHANNEL_CAPACITY: usize = 32;
|
||||
@ -30,6 +34,8 @@ const ETH_RPC_CHANNEL_CAPACITY: usize = 32;
|
||||
const VFS_CHANNEL_CAPACITY: usize = 1_000;
|
||||
const ENCRYPTOR_CHANNEL_CAPACITY: usize = 32;
|
||||
const CAP_CHANNEL_CAPACITY: usize = 1_000;
|
||||
#[cfg(feature = "llm")]
|
||||
const LLM_CHANNEL_CAPACITY: usize = 32;
|
||||
|
||||
// const QNS_SEPOLIA_ADDRESS: &str = "0x9e5ed0e7873E0d7f10eEb6dE72E87fE087A12776";
|
||||
|
||||
@ -46,24 +52,21 @@ async fn main() {
|
||||
// console_subscriber::init();
|
||||
|
||||
// DEMO ONLY: remove all CLI arguments
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let home_directory_path = &args[1];
|
||||
// let home_directory_path = "home";
|
||||
// create home directory if it does not already exist
|
||||
if let Err(e) = fs::create_dir_all(home_directory_path).await {
|
||||
panic!("failed to create home directory: {:?}", e);
|
||||
}
|
||||
// read PKI from websocket endpoint served by public RPC
|
||||
// if you get rate-limited or something, pass in your own RPC as a boot argument
|
||||
let mut rpc_url = "".to_string();
|
||||
let matches = Command::new("Uqbar")
|
||||
.version("0.1.0")
|
||||
.author("Uqbar DAO")
|
||||
.about("A decentralized operating system")
|
||||
.arg(arg!([home] "Path to home directory").required(true))
|
||||
.arg(arg!(--rpc <WS_URL> "Ethereum RPC endpoint (must be wss://)").required(true))
|
||||
.arg(arg!(--llm <LLM_URL> "LLM endpoint"))
|
||||
.get_matches();
|
||||
let home_directory_path = matches.get_one::<String>("home").unwrap();
|
||||
let rpc_url = matches.get_one::<String>("rpc").unwrap();
|
||||
let llm_url = matches.get_one::<String>("llm");
|
||||
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if arg == "--rpc" {
|
||||
// Check if the next argument exists and is not another flag
|
||||
if i + 1 < args.len() && !args[i + 1].starts_with('-') {
|
||||
rpc_url = args[i + 1].clone();
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "llm"))]
|
||||
if let Some(llm_url) = llm_url {
|
||||
panic!("You passed in --llm {:?} but you do not have the llm feature enabled. Please re-run with `--features llm`", llm_url);
|
||||
}
|
||||
|
||||
// kernel receives system messages via this channel, all other modules send messages
|
||||
@ -98,6 +101,10 @@ async fn main() {
|
||||
// encryptor handles end-to-end encryption for client messages
|
||||
let (encryptor_sender, encryptor_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(ENCRYPTOR_CHANNEL_CAPACITY);
|
||||
// optional llm extension
|
||||
#[cfg(feature = "llm")]
|
||||
let (llm_sender, llm_receiver): (MessageSender, MessageReceiver) =
|
||||
mpsc::channel(LLM_CHANNEL_CAPACITY);
|
||||
// terminal receives prints via this channel, all other modules send prints
|
||||
let (print_sender, print_receiver): (PrintSender, PrintReceiver) =
|
||||
mpsc::channel(TERMINAL_CHANNEL_CAPACITY);
|
||||
@ -214,11 +221,57 @@ async fn main() {
|
||||
|
||||
println!("registration complete!");
|
||||
|
||||
let mut runtime_extensions = vec![
|
||||
(
|
||||
ProcessId::new(Some("filesystem"), "sys", "uqbar"),
|
||||
fs_message_sender,
|
||||
false,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("http_server"), "sys", "uqbar"),
|
||||
http_server_sender,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("http_client"), "sys", "uqbar"),
|
||||
http_client_sender,
|
||||
false,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("eth_rpc"), "sys", "uqbar"),
|
||||
eth_rpc_sender,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("vfs"), "sys", "uqbar"),
|
||||
vfs_message_sender,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ProcessId::new(Some("encryptor"), "sys", "uqbar"),
|
||||
encryptor_sender,
|
||||
false,
|
||||
),
|
||||
];
|
||||
|
||||
#[cfg(feature = "llm")]
|
||||
{
|
||||
if llm_url.is_none() {
|
||||
panic!("You did not pass in --llm <LLM_URL> but you have the llm feature enabled. Please re-run with `--llm <LLM_URL>`");
|
||||
}
|
||||
runtime_extensions.push((
|
||||
ProcessId::new(Some("llm"), "sys", "uqbar"), // TODO llm:extensions:uqbar ?
|
||||
llm_sender,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
let (kernel_process_map, manifest, vfs_messages) = filesystem::load_fs(
|
||||
our.name.clone(),
|
||||
home_directory_path.clone(),
|
||||
decoded_keyfile.file_key,
|
||||
fs_config,
|
||||
runtime_extensions.clone(),
|
||||
)
|
||||
.await
|
||||
.expect("fs load failed!");
|
||||
@ -252,12 +305,7 @@ async fn main() {
|
||||
network_error_receiver,
|
||||
kernel_debug_message_receiver,
|
||||
net_message_sender.clone(),
|
||||
fs_message_sender,
|
||||
http_server_sender,
|
||||
http_client_sender,
|
||||
eth_rpc_sender,
|
||||
vfs_message_sender,
|
||||
encryptor_sender,
|
||||
runtime_extensions,
|
||||
));
|
||||
tasks.spawn(net::networking(
|
||||
our.clone(),
|
||||
@ -315,7 +363,18 @@ async fn main() {
|
||||
encryptor_receiver,
|
||||
print_sender.clone(),
|
||||
));
|
||||
|
||||
#[cfg(feature = "llm")]
|
||||
{
|
||||
tasks.spawn(llm::llm(
|
||||
our.name.clone(),
|
||||
kernel_message_sender.clone(),
|
||||
llm_receiver,
|
||||
llm_url.unwrap().to_string(),
|
||||
print_sender.clone(),
|
||||
));
|
||||
}
|
||||
// if a runtime task exits, try to recover it,
|
||||
// unless it was terminal signaling a quit
|
||||
let quit_msg: String = tokio::select! {
|
||||
Some(Ok(res)) = tasks.join_next() => {
|
||||
format!(
|
||||
|
Loading…
Reference in New Issue
Block a user