2026-07-12 06:14:34 +00:00
|
|
|
mod hardware_view;
|
feat(mvp-chat): local e2e chat on cuda gpu
Stand up an interactive end-to-end chat over a CUDA GPU, provisioning a Dockerized node that loads a GGUF model and serves prompts over TCP.
- prompt_rpc: add the newline-JSON prompt protocol (`SubmitPrompt` + `PromptEvent::{TextDelta,Done,Fault}`) carried over TCP
- mvp_chat: add an interactive REPL client connecting to the prompt RPC port (default 127.0.0.1:19777)
- mvp_orch_one_node / mvp_one_node_chat: add the single-node orchestrator that provisions a `LocalDockerPlugin` node, loads `bartowski/Llama-3.2-1B-Instruct-GGUF` (Q4_K_M), and exposes the prompt RPC listener with boot/route/weight timeouts
- mvp_node: add the GPU worker binary that spawns `tinygrad_worker.py` (default device CUDA) and ships runtime telemetry via a `ClusterFrameSink`
- vastai_provisioning / bootstrap_datastream: add the vast.ai provider adapter (`VastAiProvisioningConfig`, `VastAiLeaseClient`) wrapping `swactor_vastai`, plus a bridge that folds provision stdout onto a per-node datastream
- apps/mvp-node: add CUDA base/runtime Dockerfiles (nvidia/cuda 12.6.3, tinygrad 0.12.0, sshd), `mvp_entrypoint.sh` (sshd + mvp-node, held for postmortem), `local_docker_e2e.sh`, the GGUF tinygrad worker, and one-node-chat/bootstrap/vastai guarantee tests
Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-07-01 08:44:25 +00:00
|
|
|
mod live_explorer;
|
2026-02-09 09:04:57 +00:00
|
|
|
mod server;
|
2026-06-25 07:29:16 +00:00
|
|
|
mod store;
|
|
|
|
|
pub mod swactor;
|
|
|
|
|
pub mod view;
|
2026-06-05 07:25:43 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
use std::sync::Arc;
|
2026-06-05 07:25:43 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
use datastream::frame::{ChannelId, Frame, Lifetime, NodeId, Position, StreamId};
|
|
|
|
|
use parking_lot::Mutex;
|
|
|
|
|
use serde::Serialize;
|
|
|
|
|
use tokio::sync::broadcast;
|
2026-02-09 09:04:57 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
use crate::store::DashboardStore;
|
|
|
|
|
use crate::view::{DashboardView, ViewRegistry};
|
refactor: remove dead code, consolidate files (#52)
Remove the unused TCP transport and dead CLI/simulation scaffolding and collapse scattered single-purpose modules into consolidated files across the dashboard, process, and simulation crates.
- crates/transport: drop the TCP transport (src/tcp.rs and its tcp feature), leaving only ed25519 identity and encoding utilities behind the iroh transport
- crates/dashboard: collapse actor_detail_html/actors_html/dashboard_html/topology_html into a single html.rs, drop command/parse.rs, and inline the trace types into lib.rs
- crates/process: fold driver, pipeline_types, queue, subscriber, waker, and local pipes/signal/wait into local/mod.rs, pipeline.rs, and a unified types.rs, consolidating the public re-exports
- crates/simulation: remove the ci subdirectory (local_sim, sim) and dead node/config/trace modules, and flatten the distribution subdirectory into top-level files
- crates/datastore: remove the unused store_cli, cli, and in-memory storage, and deduplicate crypto.rs across datastore and distribution (about 190 lines of shared code removed)
- crates/distribution: drop dead codec code and trim the messages module
Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-02-25 14:33:04 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Configuration for the datastream dashboard server.
|
2026-02-09 09:04:57 +00:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct DashboardConfig {
|
|
|
|
|
pub port: u16,
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Number of raw frame events retained by the SSE channel for slow clients.
|
|
|
|
|
pub frame_buffer: usize,
|
|
|
|
|
/// Number of recent raw frames retained for `/api/frames`.
|
|
|
|
|
pub raw_frame_history: usize,
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for DashboardConfig {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
port: 9090,
|
2026-06-25 07:29:16 +00:00
|
|
|
frame_buffer: 1024,
|
|
|
|
|
raw_frame_history: 1024,
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// JSON shape emitted for each incoming datastream frame.
|
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
|
|
|
pub struct FrameEvent {
|
|
|
|
|
pub stream: StreamEvent,
|
|
|
|
|
pub channel: String,
|
|
|
|
|
pub position: u64,
|
|
|
|
|
pub payload: Vec<u8>,
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
|
|
|
pub struct StreamEvent {
|
|
|
|
|
pub node: String,
|
|
|
|
|
pub life: u64,
|
|
|
|
|
}
|
2026-06-05 07:25:43 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
impl FrameEvent {
|
|
|
|
|
pub fn new(stream: &StreamId, frame: &Frame) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
stream: StreamEvent {
|
|
|
|
|
node: stream.node.as_str().to_string(),
|
|
|
|
|
life: stream.life.0,
|
|
|
|
|
},
|
2026-07-12 06:14:34 +00:00
|
|
|
channel: frame.channel.to_string(),
|
2026-06-25 07:29:16 +00:00
|
|
|
position: frame.position.0,
|
|
|
|
|
payload: frame.payload.clone(),
|
|
|
|
|
}
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
pub(crate) fn to_datastream_parts(&self) -> Option<(StreamId, Frame)> {
|
|
|
|
|
let stream = StreamId::new(NodeId::new(&self.stream.node), Lifetime(self.stream.life));
|
2026-07-12 06:14:34 +00:00
|
|
|
let channel = self
|
|
|
|
|
.channel
|
|
|
|
|
.parse::<u32>()
|
|
|
|
|
.map(ChannelId)
|
|
|
|
|
.unwrap_or(ChannelId(0));
|
|
|
|
|
let frame = Frame::new(channel, Position(self.position), self.payload.clone());
|
2026-06-25 07:29:16 +00:00
|
|
|
Some((stream, frame))
|
2026-02-19 14:39:33 +00:00
|
|
|
}
|
2026-06-25 07:29:16 +00:00
|
|
|
}
|
2026-02-19 14:39:33 +00:00
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Handle to the read-only dashboard server.
|
|
|
|
|
///
|
|
|
|
|
/// The handle's data path publishes observed datastream frames to HTTP clients
|
|
|
|
|
/// and registered views. It does not send signals back to producers or mutate
|
|
|
|
|
/// runtime state.
|
|
|
|
|
pub struct DashboardHandle {
|
|
|
|
|
port: u16,
|
|
|
|
|
frames: broadcast::Sender<FrameEvent>,
|
|
|
|
|
store: Arc<DashboardStore>,
|
|
|
|
|
views: Arc<ViewRegistry>,
|
|
|
|
|
shutdown_notify: Arc<tokio::sync::Notify>,
|
|
|
|
|
standalone_rt: Mutex<Option<tokio::runtime::Runtime>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DashboardHandle {
|
|
|
|
|
/// Register a read-only view. External crates can keep their interpretation
|
|
|
|
|
/// code beside their component and plug it into this registry.
|
|
|
|
|
pub fn register_view(&self, view: Arc<dyn DashboardView>) {
|
|
|
|
|
self.views.register(view);
|
2026-05-29 08:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Publish one incoming datastream frame to raw clients and all matching views.
|
|
|
|
|
pub fn ingest(&self, stream: &StreamId, frame: &Frame) {
|
|
|
|
|
let event = self.store.ingest(stream, frame);
|
|
|
|
|
let _ = self.frames.send(event);
|
2026-05-29 08:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Publish an already-serialized frame event to raw clients and views.
|
|
|
|
|
pub fn publish(&self, event: FrameEvent) {
|
|
|
|
|
self.store.publish(event.clone());
|
|
|
|
|
let _ = self.frames.send(event);
|
2026-02-13 14:42:10 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Stop the HTTP server.
|
2026-02-09 09:04:57 +00:00
|
|
|
pub fn shutdown(&self) {
|
2026-02-19 14:39:33 +00:00
|
|
|
self.shutdown_notify.notify_waiters();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Start the HTTP server on an existing Tokio runtime.
|
2026-02-19 14:39:33 +00:00
|
|
|
pub fn start_http(&self, handle: tokio::runtime::Handle) {
|
2026-06-25 07:29:16 +00:00
|
|
|
let state = server::AppState {
|
|
|
|
|
frames: self.frames.clone(),
|
|
|
|
|
store: Arc::clone(&self.store),
|
|
|
|
|
views: Arc::clone(&self.views),
|
|
|
|
|
shutdown_notify: Arc::clone(&self.shutdown_notify),
|
|
|
|
|
};
|
2026-02-19 14:39:33 +00:00
|
|
|
let port = self.port;
|
|
|
|
|
handle.spawn(async move {
|
2026-06-25 07:29:16 +00:00
|
|
|
server::run_server(state, port).await;
|
2026-02-19 14:39:33 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Start the HTTP server on a standalone Tokio runtime.
|
2026-02-19 14:39:33 +00:00
|
|
|
pub fn start_http_standalone(&self) {
|
|
|
|
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
|
|
|
.worker_threads(1)
|
|
|
|
|
.enable_all()
|
|
|
|
|
.build()
|
|
|
|
|
.expect("failed to create tokio runtime for dashboard HTTP");
|
|
|
|
|
let handle = rt.handle().clone();
|
2026-06-25 07:29:16 +00:00
|
|
|
*self.standalone_rt.lock() = Some(rt);
|
2026-02-19 14:39:33 +00:00
|
|
|
self.start_http(handle);
|
|
|
|
|
}
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-25 07:29:16 +00:00
|
|
|
/// Create the datastream dashboard state.
|
2026-02-09 09:04:57 +00:00
|
|
|
///
|
2026-06-25 07:29:16 +00:00
|
|
|
/// The HTTP server is not started until `start_http` or `start_http_standalone`
|
|
|
|
|
/// is called.
|
2026-02-09 09:04:57 +00:00
|
|
|
pub fn start_dashboard(config: DashboardConfig) -> DashboardHandle {
|
2026-06-25 07:29:16 +00:00
|
|
|
let views = Arc::new(ViewRegistry::new());
|
2026-07-12 06:14:34 +00:00
|
|
|
views.register(Arc::new(live_explorer::LiveDatastreamExplorer::default()));
|
|
|
|
|
views.register(Arc::new(hardware_view::HardwareDashboardView::default()));
|
2026-06-25 07:29:16 +00:00
|
|
|
views.register(swactor::worker_view());
|
|
|
|
|
let store = Arc::new(DashboardStore::new(
|
|
|
|
|
config.raw_frame_history,
|
|
|
|
|
Arc::clone(&views),
|
2026-02-11 15:23:26 +00:00
|
|
|
));
|
2026-06-25 07:29:16 +00:00
|
|
|
let (frames, _) = broadcast::channel(config.frame_buffer.max(1));
|
2026-02-09 09:04:57 +00:00
|
|
|
DashboardHandle {
|
2026-06-25 07:29:16 +00:00
|
|
|
port: config.port,
|
|
|
|
|
frames,
|
2026-02-09 09:04:57 +00:00
|
|
|
store,
|
2026-06-25 07:29:16 +00:00
|
|
|
views,
|
|
|
|
|
shutdown_notify: Arc::new(tokio::sync::Notify::new()),
|
2026-02-19 14:39:33 +00:00
|
|
|
standalone_rt: Mutex::new(None),
|
2026-02-09 09:04:57 +00:00
|
|
|
}
|
|
|
|
|
}
|