mirror of
https://github.com/alphaXiv/OpenResearch.git
synced 2026-11-12 10:05:24 +08:00
cpu sandboxes (#10)
This commit is contained in:
Generated
+1
-1
@@ -702,7 +702,7 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "openresearch-cli"
|
||||
version = "0.1.20"
|
||||
version = "0.1.21"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "openresearch-cli"
|
||||
version = "0.1.20"
|
||||
version = "0.1.21"
|
||||
edition = "2021"
|
||||
description = "OpenResearch CLI (orx) — Rust port"
|
||||
repository = "https://github.com/alphaXiv/openresearch-cli"
|
||||
|
||||
@@ -41,10 +41,10 @@ Run the tests with `cargo test`.
|
||||
| `orx logout` | Removes the stored token. |
|
||||
| `orx install-skills [--agent claude\|codex\|opencode\|cursor\|all]` | Installs the `orx` skill shim into local coding agents (Claude Code, Codex, OpenCode, Cursor) so they auto-discover the CLI (`orx login` also offers this). |
|
||||
| `orx projects [--all]` | Lists your projects, grouped by organization. `--all` includes archived. |
|
||||
| `orx compute [--gpu <id>] [--count <n>]` | Lists the GPU compute catalog, sorted by price. |
|
||||
| `orx compute [--gpu <id>] [--count <n>] \| --cpu]` | Lists the GPU compute catalog, or CPU-only offers with `--cpu`, sorted by price. |
|
||||
| `orx exp status <expId>` | Shows an experiment's status, branch, parent, run command, and latest run, plus a local `git diff` recipe for what the run changed. |
|
||||
| `orx exp cmd <expId> [--set <command>]` | Views or sets the experiment's run command. |
|
||||
| `orx exp run <expId> (--gpu <id> [--count <n>] [--disk <gb>] \| --sandbox <id>)` | Launches a run on new or existing compute. |
|
||||
| `orx exp run <expId> (--gpu <id> [--count <n>] [--disk <gb>] \| --cpu <flavor> [--vcpus <n>] \| --sandbox <id>)` | Launches a run on new GPU, new CPU-only, or existing compute. |
|
||||
| `orx exp cancel <expId>` | Cancels the in-flight run. |
|
||||
| `orx lit "<query>" [--limit <n>] [--json]` | Full-text search alphaXiv's paper corpus (no login required). |
|
||||
| `orx paper <id\|url> [--full]` | Fetch a paper's machine-readable report, or its full text with `--full`. |
|
||||
|
||||
@@ -86,7 +86,7 @@ orx logout # remove the stored token
|
||||
|---|---|
|
||||
| `orx create-project <orgId> --name "<n>" [--repo <owner/repo>]` | Create a project **and its baseline (root node)**: bound to a GitHub repo, or on a fresh blank repo when `--repo` is omitted. See below. |
|
||||
| `orx create-experiment <projectId> --title "<t>" [...]` | Add an experiment node; prints its git branch. See below. |
|
||||
| `orx compute [--gpu <id>] [--count <n>]` | List the GPU compute catalog (price-sorted). See below. |
|
||||
| `orx compute [--gpu <id>] [--count <n>] \| --cpu]` | List the GPU compute catalog, or CPU-only offers with `--cpu` (price-sorted). See below. |
|
||||
| `orx exp status/cmd/run/cancel/wait <expId>` | Inspect, run, cancel, and wait on a single experiment node. `status` prints the node's branch, its parent's branch, the latest run's full commit SHA, and a ready-to-paste local `git diff` recipe. See below. |
|
||||
| `orx exp desc <expId> [--set "<text>" \| --stdin]` | Read or overwrite the experiment's description (free-form notes). See below. |
|
||||
|
||||
@@ -343,7 +343,8 @@ orx create-experiment <projectId> --title "Baseline"
|
||||
|
||||
Each experiment node has a **run command** (the shell command that trains/evaluates
|
||||
it) and is launched on **compute** you choose at run time. Compute is *not* stored
|
||||
on the node — you pick a GPU (or an existing sandbox) each time you launch.
|
||||
on the node — you pick a GPU, a CPU-only instance, or an existing sandbox each time
|
||||
you launch.
|
||||
|
||||
```sh
|
||||
orx exp status <expId> # status, branch, parent, run command, latest run + commit, local diff recipe
|
||||
@@ -351,7 +352,9 @@ orx exp cmd <expId> # print the current run command
|
||||
orx exp cmd <baseId> --set "bash run.sh" # set it ONCE on the baseline; children inherit it
|
||||
orx compute # browse GPU offers (price-sorted)
|
||||
orx compute --gpu H100_SXM --count 1 # filter the catalog
|
||||
orx exp run <expId> --gpu H100_SXM --count 1 [--disk 100] # launch on a NEW instance
|
||||
orx compute --cpu # browse CPU-only offers (price-sorted)
|
||||
orx exp run <expId> --gpu H100_SXM --count 1 [--disk 100] # launch on a NEW GPU instance
|
||||
orx exp run <expId> --cpu cpu5c --vcpus 8 # launch on a NEW CPU-only instance
|
||||
orx exp run <expId> --sandbox <sandboxId> # launch on an EXISTING node
|
||||
orx exp cancel <expId> # cancel the in-flight run
|
||||
```
|
||||
@@ -370,14 +373,19 @@ Rules and notes:
|
||||
safety net, `orx exp run` refuses a child whose branch has **no changes over its
|
||||
parent** (the tell-tale of "queued before pushing") — push and retry, or pass
|
||||
`--force` to run the unchanged code deliberately.
|
||||
- **Pick compute with exactly one of `--gpu` or `--sandbox`.** With `--gpu`,
|
||||
`--count` defaults to `1` and `--disk` to `100` (GB). New instances are
|
||||
- **Pick compute with exactly one of `--gpu`, `--cpu`, or `--sandbox`.** With
|
||||
`--gpu`, `--count` defaults to `1` and `--disk` to `100` (GB). New instances are
|
||||
**RunPod-only** — the server picks the cheapest matching RunPod offer for the
|
||||
chosen (gpu, count); browse valid gpu ids and prices with `orx compute`.
|
||||
- **GPU ids are exact enum strings, not family names.** `--gpu H100` is invalid —
|
||||
the variant suffix is part of the id (`H100_SXM`, `H100_PCIE`, `A100_SXM_80GB`,
|
||||
`RTX_4090`, …). Use the exact `GPU` column value from `orx compute`; run it
|
||||
first if unsure.
|
||||
- **Use `--cpu` for GPU-less work** (data prep, eval harnesses, CPU-bound papers).
|
||||
The flavor is one of `cpu5c` (compute), `cpu5g` (general), or `cpu5m` (memory);
|
||||
`--vcpus` is one of `2`, `8`, `32` (default `8`). Browse offers with
|
||||
`orx compute --cpu`. CPU instances size their disk from the vCPU count, so there
|
||||
is no `--disk` knob.
|
||||
- `orx exp run` **queues** the run and returns immediately — it does not wait.
|
||||
Follow progress with `orx runs <projectId>` and `orx logs <runId>`, or block
|
||||
with `orx exp wait` (below).
|
||||
|
||||
@@ -111,6 +111,30 @@ pub struct ListCatalog {
|
||||
pub offers: Vec<GpuOffer>,
|
||||
}
|
||||
|
||||
/// A single CPU-only offer from the CPU catalog (`GET /compute/catalog/cpu`).
|
||||
/// Sibling to [`GpuOffer`]; CPU instances live in their own RunPod-only catalog.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CpuOffer {
|
||||
pub provider: String,
|
||||
pub offer_id: String,
|
||||
/// Flavor id: cpu5c (compute), cpu5g (general), or cpu5m (memory-optimized).
|
||||
pub cpu_flavor: String,
|
||||
/// Virtual CPUs allocated to the instance.
|
||||
pub vcpus: f64,
|
||||
/// System RAM in GB.
|
||||
pub ram_gb: f64,
|
||||
pub price_per_hour: f64,
|
||||
/// Disk storage rate while running, USD per GB per hour.
|
||||
pub disk_per_gb_hour: f64,
|
||||
pub region: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ListCpuCatalog {
|
||||
pub offers: Vec<CpuOffer>,
|
||||
}
|
||||
|
||||
/// Response of `GET /experiments/{id}`: the experiment plus its most recent run.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -707,6 +731,10 @@ pub async fn list_catalog(creds: &Credentials) -> Result<ListCatalog> {
|
||||
api_get(creds, "/compute/catalog").await
|
||||
}
|
||||
|
||||
pub async fn list_cpu_catalog(creds: &Credentials) -> Result<ListCpuCatalog> {
|
||||
api_get(creds, "/compute/catalog/cpu").await
|
||||
}
|
||||
|
||||
pub async fn get_experiment(creds: &Credentials, exp_id: &str) -> Result<GetExperimentResult> {
|
||||
api_get(creds, &format!("/experiments/{}", exp_id)).await
|
||||
}
|
||||
|
||||
+43
-3
@@ -1,17 +1,25 @@
|
||||
//! The `compute` command. Lists the GPU offer catalog as a price-sorted table.
|
||||
//! The `compute` command. Lists the GPU offer catalog as a price-sorted table,
|
||||
//! or the CPU-only catalog with `--cpu`.
|
||||
//!
|
||||
//! The catalog endpoint spans every provider, but experiment runs launched on a
|
||||
//! *new* instance (`orx exp run --gpu ...`) are RunPod-only — the server
|
||||
//! resolves the cheapest matching RunPod offer for the chosen (gpu, count). So
|
||||
//! this command filters to RunPod offers: everything it lists is launchable.
|
||||
//! CPU offers are RunPod-only to begin with, so no filtering is needed there.
|
||||
|
||||
use crate::client::list_catalog;
|
||||
use crate::client::{list_catalog, list_cpu_catalog};
|
||||
use crate::error::{require_credentials, Result};
|
||||
use crate::output::print_table;
|
||||
|
||||
/// Lists the GPU compute catalog, optionally filtered by gpu id and/or count.
|
||||
/// Lists the compute catalog. With `--cpu`, lists CPU-only offers; otherwise the
|
||||
/// GPU catalog, optionally filtered by gpu id and/or count.
|
||||
pub async fn run(args: crate::ComputeArgs) -> Result<()> {
|
||||
let creds = require_credentials().await;
|
||||
|
||||
if args.cpu {
|
||||
return run_cpu(&creds).await;
|
||||
}
|
||||
|
||||
let offers = list_catalog(&creds).await?.offers;
|
||||
|
||||
// The API already returns offers sorted by price ascending; keep that order.
|
||||
@@ -56,3 +64,35 @@ pub async fn run(args: crate::ComputeArgs) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Lists the CPU-only offer catalog as a price-sorted table. Launch one with
|
||||
/// `orx exp run --cpu <flavor> --vcpus <n>`.
|
||||
async fn run_cpu(creds: &crate::config::Credentials) -> Result<()> {
|
||||
let offers = list_cpu_catalog(creds).await?.offers;
|
||||
|
||||
if offers.is_empty() {
|
||||
println!("No CPU compute offers available.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let rows: Vec<Vec<String>> = offers
|
||||
.iter()
|
||||
.map(|o| {
|
||||
vec![
|
||||
o.cpu_flavor.clone(),
|
||||
format!("{:.0}", o.vcpus),
|
||||
format!("${:.2}", o.price_per_hour),
|
||||
format!("{:.0}", o.ram_gb),
|
||||
o.region.clone().unwrap_or_else(|| "—".to_string()),
|
||||
o.provider.clone(),
|
||||
]
|
||||
})
|
||||
.collect();
|
||||
|
||||
print_table(
|
||||
&["FLAVOR", "VCPUS", "$/HR", "RAM(GB)", "REGION", "PROVIDER"],
|
||||
&rows,
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+6
-2
@@ -248,10 +248,14 @@ pub struct CreateExperimentArgs {
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct ComputeArgs {
|
||||
/// Filter to one GPU id (e.g. `H100_SXM`). Case-insensitive.
|
||||
/// List CPU-only instance offers instead of the GPU catalog. CPU instances
|
||||
/// suit GPU-less experiments (data prep, eval harnesses, CPU-bound papers).
|
||||
#[arg(long)]
|
||||
pub cpu: bool,
|
||||
/// Filter to one GPU id (e.g. `H100_SXM`). Case-insensitive. GPU mode only.
|
||||
#[arg(long)]
|
||||
pub gpu: Option<String>,
|
||||
/// Filter to a specific GPU count per instance.
|
||||
/// Filter to a specific GPU count per instance. GPU mode only.
|
||||
#[arg(long)]
|
||||
pub count: Option<i64>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user