@gridlock-compute/native-worker 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -0
- package/bin/gridlock-native-worker.cjs +4 -0
- package/dist/attestation-quote.d.ts +11 -0
- package/dist/attestation-quote.js +56 -0
- package/dist/attestation.d.ts +2 -0
- package/dist/attestation.js +11 -0
- package/dist/banner.d.ts +2 -0
- package/dist/banner.js +41 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.js +34 -0
- package/dist/console-io.d.ts +2 -0
- package/dist/console-io.js +10 -0
- package/dist/dashboard.d.ts +54 -0
- package/dist/dashboard.js +247 -0
- package/dist/gpu.d.ts +4 -0
- package/dist/gpu.js +168 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/inference-ollama-worker.d.ts +9 -0
- package/dist/inference-ollama-worker.js +94 -0
- package/dist/inference.d.ts +27 -0
- package/dist/inference.js +223 -0
- package/dist/live-stats.d.ts +14 -0
- package/dist/live-stats.js +66 -0
- package/dist/lock.d.ts +2 -0
- package/dist/lock.js +46 -0
- package/dist/model-select.d.ts +3 -0
- package/dist/model-select.js +39 -0
- package/dist/ollama.d.ts +22 -0
- package/dist/ollama.js +195 -0
- package/dist/wallet.d.ts +2 -0
- package/dist/wallet.js +14 -0
- package/dist/worker.d.ts +10 -0
- package/dist/worker.js +437 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# worker-cli
|
|
2
|
+
|
|
3
|
+
Headless GPU worker for the [Gridlock](https://grid-lock.tech) decentralized inference network. Connects to the [router](https://github.com/Gridlockcompute/router) over WebSocket, registers your **EVM wallet** (`0x…` on Robinhood Chain) as operator identity, and runs chat jobs locally via **Ollama** or **vLLM**.
|
|
4
|
+
|
|
5
|
+
**Production router:** [https://api.grid-lock.tech](https://api.grid-lock.tech)
|
|
6
|
+
|
|
7
|
+
## What it is
|
|
8
|
+
|
|
9
|
+
`worker-cli` (npm package `@gridlock-compute/native-worker`) is the command-line worker client for operators who want to contribute GPU compute without a desktop UI. It:
|
|
10
|
+
|
|
11
|
+
1. Detects your hardware (GPU or CPU) and runs a short throughput benchmark
|
|
12
|
+
2. Registers with the Gridlock router (`POST /v1/workers/register`) and sets status **Active** so jobs can be dispatched
|
|
13
|
+
3. Maintains REST heartbeats and a persistent WebSocket at `/v1/ws`
|
|
14
|
+
4. Executes inference jobs pushed by the router and reports TTFT, TPOT, and token counts
|
|
15
|
+
5. Optionally attaches a TEE attestation quote at registration and computes job attestation hashes for confidential work
|
|
16
|
+
|
|
17
|
+
Use the same **0x EVM address** here as on the [web worker dashboard](https://grid-lock.tech/worker) so earnings, jobs, and connection status appear in one place.
|
|
18
|
+
|
|
19
|
+
Set your **earnings wallet** on the worker dashboard (or via `PATCH /v1/workers/{address}/earnings-wallet`). SLA misses deduct from pending worker earnings; customers receive automatic ledger credits.
|
|
20
|
+
|
|
21
|
+
Stake native ETH separately from the web console for fee-share boosts — the CLI never needs your private key.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Headless operation** — no Electron, no browser; ideal for servers and Linux GPU boxes
|
|
26
|
+
- **EVM identity** — validates `0x` addresses locally before registration
|
|
27
|
+
- **Live terminal dashboard** — status table with uptime, jobs, throughput, queue depth, and a progress bar while inference runs
|
|
28
|
+
- **WebSocket job dispatch** — real-time job push from the router with automatic reconnect
|
|
29
|
+
- **Hardware detection** — NVIDIA (`nvidia-smi`), AMD (`rocm-smi`), or `CPU · {model}` when no inference GPU is present
|
|
30
|
+
- **Benchmark mode** — `--benchmark` runs throughput test and exits
|
|
31
|
+
- **Confidential jobs** — registration attestation quote + per-job SHA-256 hash for TEE-tier work
|
|
32
|
+
- **Configurable roles** — register as Prefill, Decode, or other worker roles via env/flag
|
|
33
|
+
|
|
34
|
+
## Prerequisites
|
|
35
|
+
|
|
36
|
+
- **Node.js** 18 or later
|
|
37
|
+
- **NVIDIA GPU** with CUDA drivers (recommended for local inference)
|
|
38
|
+
- **Ollama** ([download](https://ollama.com/download)) — recommended on Windows and macOS
|
|
39
|
+
- **vLLM** — recommended on Linux/WSL with an OpenAI-compatible server on port 8000
|
|
40
|
+
- An **EVM wallet address** (`0x…`) — private key never required in the CLI
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
**From npm (recommended):**
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install -g @gridlock-compute/native-worker
|
|
48
|
+
gridlock-native-worker --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**From source:**
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/Gridlockcompute/worker-cli.git
|
|
55
|
+
cd worker-cli
|
|
56
|
+
npm install
|
|
57
|
+
npm run build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Install globally from source (optional):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm link
|
|
64
|
+
gridlock-native-worker --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or run directly:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
node dist/index.js --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# 1. Install Ollama (https://ollama.com/download) or start vLLM on this machine
|
|
77
|
+
|
|
78
|
+
# 2. Start the worker — connects to https://api.grid-lock.tech
|
|
79
|
+
gridlock-native-worker --wallet 0xYourEvmAddress
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
On first run with Ollama, the worker lists installed models and prompts you to pick one (or pulls the default if none are installed).
|
|
83
|
+
|
|
84
|
+
If you already have models, you'll see a selector like:
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Installed Ollama models:
|
|
88
|
+
|
|
89
|
+
1. llama3.2:3b (2.0 GB)
|
|
90
|
+
2. phi3:mini (2.2 GB)
|
|
91
|
+
3. Pull llama3.1:8b (default — not installed yet)
|
|
92
|
+
|
|
93
|
+
Select model [1-3, default 1]:
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Pass `--model llama3.2:3b` or set `GRIDLOCK_OLLAMA_MODEL` to skip the prompt.
|
|
97
|
+
|
|
98
|
+
Windows PowerShell example:
|
|
99
|
+
|
|
100
|
+
```powershell
|
|
101
|
+
npm install
|
|
102
|
+
npm run build
|
|
103
|
+
node dist/index.js --wallet 0xYourEvmAddress
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Configuration
|
|
107
|
+
|
|
108
|
+
### CLI flags
|
|
109
|
+
|
|
110
|
+
| Flag | Default | Description |
|
|
111
|
+
|------|---------|-------------|
|
|
112
|
+
| `--wallet <address>` | — | EVM wallet address `0x…` (**required**, or set `GRIDLOCK_WALLET`) |
|
|
113
|
+
| `--inference <backend>` | `auto` | `auto`, `ollama`, or `vllm` |
|
|
114
|
+
| `--model <tag>` | — | Ollama model (e.g. `llama3.2:3b`); interactive picker if omitted and multiple models exist |
|
|
115
|
+
| `--benchmark` | — | Run benchmark only, then exit |
|
|
116
|
+
| `--version` | — | Print version |
|
|
117
|
+
| `--help` | — | Print help |
|
|
118
|
+
|
|
119
|
+
### Environment variables
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Description |
|
|
122
|
+
|----------|---------|-------------|
|
|
123
|
+
| `GRIDLOCK_WALLET` | — | EVM address (alternative to `--wallet`) |
|
|
124
|
+
| `GRIDLOCK_EARNINGS_WALLET` | operator wallet | Payout wallet sent at registration (`earnings_wallet`) |
|
|
125
|
+
| `GRIDLOCK_INFERENCE` | `auto` | Inference backend: `auto`, `ollama`, or `vllm` |
|
|
126
|
+
| `GRIDLOCK_OLLAMA_URL` | Ollama on this machine (port 11434) | Override if Ollama listens elsewhere |
|
|
127
|
+
| `GRIDLOCK_OLLAMA_MODEL` | `llama3.1:8b` | Ollama model tag |
|
|
128
|
+
| `GRIDLOCK_VLLM_URL` | vLLM on this machine (port 8000) | OpenAI-compatible vLLM base URL |
|
|
129
|
+
| `GRIDLOCK_VLLM_MODEL` | `meta-llama/Llama-3.1-8B-Instruct` | vLLM model id |
|
|
130
|
+
| `GRIDLOCK_ROLE` | `Prefill` | Worker role sent at registration |
|
|
131
|
+
| `GRIDLOCK_TEE_CAPABLE` | `false` | Set `true` to register as TEE-capable |
|
|
132
|
+
| `GRIDLOCK_ATTESTATION_QUOTE_FILE` | — | Path to production NRAS/SEV quote JSON for registration |
|
|
133
|
+
| `GRIDLOCK_ATTESTATION_QUOTE_JSON` | — | Inline attestation quote JSON (alternative to file) |
|
|
134
|
+
| `GRIDLOCK_TEE_TYPE` | `nvidia_cc` | TEE type in dev quotes (`nvidia_cc`, `amd_sev_snp`) |
|
|
135
|
+
| `GRIDLOCK_PLAIN_LOGS` | — | Set `true` to disable the live dashboard and use plain log lines |
|
|
136
|
+
|
|
137
|
+
All workers connect to **[https://api.grid-lock.tech](https://api.grid-lock.tech)** for registration, heartbeats, and WebSocket job dispatch. Inference (Ollama/vLLM) runs on your machine.
|
|
138
|
+
|
|
139
|
+
Only **one worker process per wallet** is allowed. A second instance will exit immediately (lock file in `~/.gridlock/`).
|
|
140
|
+
|
|
141
|
+
## Usage examples
|
|
142
|
+
|
|
143
|
+
**Standard run:**
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
export GRIDLOCK_WALLET=0xYourEvmAddress
|
|
147
|
+
gridlock-native-worker
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Force vLLM backend:**
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
gridlock-native-worker --wallet 0xYourEvmAddress --inference vllm
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Benchmark only (no registration):**
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
gridlock-native-worker --wallet 0xYourEvmAddress --benchmark
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**TEE / confidential registration (dev attestation quote from router challenge):**
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
GRIDLOCK_TEE_CAPABLE=true gridlock-native-worker --wallet 0xYourEvmAddress
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
For production CC GPUs, provide a vendor attestation quote:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
export GRIDLOCK_TEE_CAPABLE=true
|
|
172
|
+
export GRIDLOCK_ATTESTATION_QUOTE_FILE=/path/to/quote.json
|
|
173
|
+
gridlock-native-worker --wallet 0xYourEvmAddress
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## On-chain registration
|
|
177
|
+
|
|
178
|
+
The CLI does **not** sign Robinhood Chain transactions itself. When the router has `WORKER_REGISTRY_ONCHAIN_ENABLED=true` and `EVM_*` contract addresses configured, the **router** may register your worker on-chain after `POST /v1/workers/register`. Staking, payouts, and billing are handled via the web dashboard and router APIs.
|
|
179
|
+
|
|
180
|
+
After starting, the worker connects to `wss://api.grid-lock.tech/v1/ws`, sends `worker:register` with `worker_type: native`, and waits for `job:new` messages.
|
|
181
|
+
|
|
182
|
+
Monitor your operator on the web: [https://grid-lock.tech/worker](https://grid-lock.tech/worker)
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm run dev # tsx watch — src/index.ts
|
|
188
|
+
npm run build # compile TypeScript → dist/
|
|
189
|
+
npm start # node dist/index.js
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Project layout:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
worker-cli/
|
|
196
|
+
├── src/
|
|
197
|
+
│ ├── index.ts # CLI entry (commander)
|
|
198
|
+
│ ├── worker.ts # WebSocket session + job loop
|
|
199
|
+
│ ├── wallet.ts # EVM address validation
|
|
200
|
+
│ ├── attestation-quote.ts # Registration TEE quotes
|
|
201
|
+
│ ├── inference.ts # Ollama / vLLM adapters
|
|
202
|
+
│ ├── ollama.ts # Ollama bootstrap
|
|
203
|
+
│ ├── gpu.ts # GPU detection
|
|
204
|
+
│ └── attestation.ts # Per-job confidential hashing
|
|
205
|
+
├── bin/
|
|
206
|
+
│ └── gridlock-native-worker.cjs
|
|
207
|
+
└── package.json
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Related repos
|
|
211
|
+
|
|
212
|
+
| Repo | Role |
|
|
213
|
+
|------|------|
|
|
214
|
+
| [router](https://github.com/Gridlockcompute/router) | Hono API — job routing, WebSocket hub, billing |
|
|
215
|
+
| [worker-desktop](https://github.com/Gridlockcompute/worker-desktop) | Electron GUI worker with setup wizard |
|
|
216
|
+
| [contracts](https://github.com/Gridlockcompute/gridlockcompute) | EVM Solidity contracts on Robinhood Chain |
|
|
217
|
+
|
|
218
|
+
**Website:** [https://grid-lock.tech](https://grid-lock.tech) · **API docs:** [https://grid-lock.tech/docs](https://grid-lock.tech/docs)
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface AttestationQuotePayload {
|
|
2
|
+
worker_pubkey: string;
|
|
3
|
+
tee_type: string;
|
|
4
|
+
nonce: string;
|
|
5
|
+
enclave_pubkey: string;
|
|
6
|
+
report_bytes: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
certificate_chain?: string[];
|
|
9
|
+
}
|
|
10
|
+
/** Resolve TEE attestation quote for worker registration (production file or dev challenge). */
|
|
11
|
+
export declare function resolveRegistrationAttestationQuote(backendUrl: string, wallet: string, teeCapable: boolean): Promise<AttestationQuotePayload | undefined>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
async function fetchChallenge(backendUrl, wallet) {
|
|
3
|
+
const base = backendUrl.replace(/\/$/, "");
|
|
4
|
+
const res = await fetch(`${base}/v1/attestation/challenge?wallet=${encodeURIComponent(wallet)}`);
|
|
5
|
+
if (!res.ok) {
|
|
6
|
+
const text = await res.text();
|
|
7
|
+
throw new Error(`attestation challenge failed (${res.status}): ${text.slice(0, 200)}`);
|
|
8
|
+
}
|
|
9
|
+
const data = (await res.json());
|
|
10
|
+
if (!data.nonce)
|
|
11
|
+
throw new Error("attestation challenge missing nonce");
|
|
12
|
+
return data.nonce;
|
|
13
|
+
}
|
|
14
|
+
function loadQuoteFromEnv() {
|
|
15
|
+
const file = process.env.GRIDLOCK_ATTESTATION_QUOTE_FILE?.trim();
|
|
16
|
+
if (file) {
|
|
17
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
18
|
+
}
|
|
19
|
+
const json = process.env.GRIDLOCK_ATTESTATION_QUOTE_JSON?.trim();
|
|
20
|
+
if (json) {
|
|
21
|
+
return JSON.parse(json);
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function buildDevAttestationQuote(wallet, nonce) {
|
|
26
|
+
const reportBytes = Buffer.from(`mock-${wallet.toLowerCase()}-${nonce}-${Date.now()}`, "utf8").toString("base64");
|
|
27
|
+
return {
|
|
28
|
+
worker_pubkey: wallet,
|
|
29
|
+
tee_type: process.env.GRIDLOCK_TEE_TYPE?.trim() || "nvidia_cc",
|
|
30
|
+
nonce,
|
|
31
|
+
enclave_pubkey: process.env.GRIDLOCK_ENCLAVE_PUBKEY?.trim() || wallet,
|
|
32
|
+
report_bytes: reportBytes,
|
|
33
|
+
timestamp: Date.now(),
|
|
34
|
+
certificate_chain: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Resolve TEE attestation quote for worker registration (production file or dev challenge). */
|
|
38
|
+
export async function resolveRegistrationAttestationQuote(backendUrl, wallet, teeCapable) {
|
|
39
|
+
if (!teeCapable)
|
|
40
|
+
return undefined;
|
|
41
|
+
const fromEnv = loadQuoteFromEnv();
|
|
42
|
+
if (fromEnv) {
|
|
43
|
+
console.log("[attestation] Using quote from GRIDLOCK_ATTESTATION_QUOTE_FILE / _JSON");
|
|
44
|
+
return fromEnv;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const nonce = await fetchChallenge(backendUrl, wallet);
|
|
48
|
+
console.log("[attestation] Dev quote from router challenge (production CC GPUs: set GRIDLOCK_ATTESTATION_QUOTE_FILE)");
|
|
49
|
+
return buildDevAttestationQuote(wallet, nonce);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
53
|
+
console.warn(`[attestation] Skipping registration quote: ${msg}`);
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
/** Must match gridlock-backend/src/attestation.ts computeJobAttestationHash. */
|
|
3
|
+
export function computeJobAttestationHash(jobId, workerAddress, response) {
|
|
4
|
+
return createHash("sha256")
|
|
5
|
+
.update(JSON.stringify({
|
|
6
|
+
jobId,
|
|
7
|
+
workerAddress,
|
|
8
|
+
response: response.slice(0, 512),
|
|
9
|
+
}))
|
|
10
|
+
.digest("hex");
|
|
11
|
+
}
|
package/dist/banner.d.ts
ADDED
package/dist/banner.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const LIME_GREEN = "\x1b[38;2;182;255;60m";
|
|
6
|
+
const RESET = "\x1b[0m";
|
|
7
|
+
const CHEVRONS = `
|
|
8
|
+
█████████ ███████████ █████ ██████████ █████ ███████ █████████ █████ ████
|
|
9
|
+
███▒▒▒▒▒███▒▒███▒▒▒▒▒███ ▒▒███ ▒▒███▒▒▒▒███ ▒▒███ ███▒▒▒▒▒███ ███▒▒▒▒▒███▒▒███ ███▒
|
|
10
|
+
███ ▒▒▒ ▒███ ▒███ ▒███ ▒███ ▒▒███ ▒███ ███ ▒▒███ ███ ▒▒▒ ▒███ ███
|
|
11
|
+
▒███ ▒██████████ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███▒███ ▒███████
|
|
12
|
+
▒███ █████ ▒███▒▒▒▒▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███▒███ ▒███▒▒███
|
|
13
|
+
▒▒███ ▒▒███ ▒███ ▒███ ▒███ ▒███ ███ ▒███ █▒▒███ ███ ▒▒███ ███ ▒███ ▒▒███
|
|
14
|
+
▒▒█████████ █████ █████ █████ ██████████ ███████████ ▒▒▒███████▒ ▒▒█████████ █████ ▒▒████
|
|
15
|
+
▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
`.trimEnd();
|
|
20
|
+
function shouldColorize() {
|
|
21
|
+
const { FORCE_COLOR, NO_COLOR } = process.env;
|
|
22
|
+
if (FORCE_COLOR !== undefined) {
|
|
23
|
+
return FORCE_COLOR !== "0" && FORCE_COLOR.toLowerCase() !== "false";
|
|
24
|
+
}
|
|
25
|
+
if (NO_COLOR !== undefined)
|
|
26
|
+
return false;
|
|
27
|
+
return process.stdout.isTTY === true;
|
|
28
|
+
}
|
|
29
|
+
function colorize(text) {
|
|
30
|
+
if (!shouldColorize())
|
|
31
|
+
return text;
|
|
32
|
+
return `${LIME_GREEN}${text}${RESET}`;
|
|
33
|
+
}
|
|
34
|
+
/** Print banner; returns how many terminal rows it consumed. */
|
|
35
|
+
export function printStartupBanner() {
|
|
36
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
37
|
+
console.log(colorize(CHEVRONS));
|
|
38
|
+
console.log(colorize(` Gridlock Native Worker v${pkg.version}`));
|
|
39
|
+
console.log();
|
|
40
|
+
return CHEVRONS.split("\n").length + 2;
|
|
41
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Gridlock API — all workers connect here. */
|
|
2
|
+
export declare const GRIDLOCK_API_URL = "https://api.grid-lock.tech";
|
|
3
|
+
export declare function getBackendUrl(): string;
|
|
4
|
+
/** @deprecated Use getBackendUrl() */
|
|
5
|
+
export declare const DEFAULT_BACKEND_URL = "https://api.grid-lock.tech";
|
|
6
|
+
/** Gridlock router — jobs, registration, WebSocket. */
|
|
7
|
+
export declare const ROUTER_URL = "https://api.grid-lock.tech";
|
|
8
|
+
/** vLLM OpenAI-compatible API on this machine (separate inference process). */
|
|
9
|
+
export declare const VLLM_BASE_URL: string;
|
|
10
|
+
/** Resolved at runtime after probing Ollama on this host. */
|
|
11
|
+
export declare let OLLAMA_URL: string;
|
|
12
|
+
export declare function setOllamaUrl(url: string): void;
|
|
13
|
+
export declare const OLLAMA_URL_CANDIDATES: string[];
|
|
14
|
+
export type InferenceBackend = "auto" | "ollama" | "vllm";
|
|
15
|
+
export declare const INFERENCE_BACKEND: InferenceBackend;
|
|
16
|
+
export declare const VLLM_MODEL: string;
|
|
17
|
+
export declare const OLLAMA_MODEL: string;
|
|
18
|
+
export declare const DEFAULT_ROLE: string;
|
|
19
|
+
export declare const BENCHMARK_TOKENS = 32;
|
|
20
|
+
export declare const MAX_OUTPUT_TOKENS = 512;
|
|
21
|
+
export declare function wsUrl(httpBase: string): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Gridlock API — all workers connect here. */
|
|
2
|
+
export const GRIDLOCK_API_URL = "https://api.grid-lock.tech";
|
|
3
|
+
export function getBackendUrl() {
|
|
4
|
+
return GRIDLOCK_API_URL;
|
|
5
|
+
}
|
|
6
|
+
/** @deprecated Use getBackendUrl() */
|
|
7
|
+
export const DEFAULT_BACKEND_URL = GRIDLOCK_API_URL;
|
|
8
|
+
/** Gridlock router — jobs, registration, WebSocket. */
|
|
9
|
+
export const ROUTER_URL = GRIDLOCK_API_URL;
|
|
10
|
+
const DEFAULT_OLLAMA_PORT = 11434;
|
|
11
|
+
const DEFAULT_VLLM_PORT = 8000;
|
|
12
|
+
/** vLLM OpenAI-compatible API on this machine (separate inference process). */
|
|
13
|
+
export const VLLM_BASE_URL = (process.env.GRIDLOCK_VLLM_URL ?? `http://127.0.0.1:${DEFAULT_VLLM_PORT}/v1`).replace(/\/$/, "");
|
|
14
|
+
/** Resolved at runtime after probing Ollama on this host. */
|
|
15
|
+
export let OLLAMA_URL = (process.env.GRIDLOCK_OLLAMA_URL ?? `http://127.0.0.1:${DEFAULT_OLLAMA_PORT}`).replace(/\/$/, "");
|
|
16
|
+
export function setOllamaUrl(url) {
|
|
17
|
+
OLLAMA_URL = url.replace(/\/$/, "");
|
|
18
|
+
}
|
|
19
|
+
export const OLLAMA_URL_CANDIDATES = [
|
|
20
|
+
process.env.GRIDLOCK_OLLAMA_URL?.replace(/\/$/, ""),
|
|
21
|
+
`http://127.0.0.1:${DEFAULT_OLLAMA_PORT}`,
|
|
22
|
+
].filter(Boolean);
|
|
23
|
+
export const INFERENCE_BACKEND = (process.env.GRIDLOCK_INFERENCE ?? "auto");
|
|
24
|
+
export const VLLM_MODEL = process.env.GRIDLOCK_VLLM_MODEL ?? process.env.GRIDLOCK_MODEL ?? "meta-llama/Llama-3.1-8B-Instruct";
|
|
25
|
+
export const OLLAMA_MODEL = process.env.GRIDLOCK_OLLAMA_MODEL ?? "llama3.1:8b";
|
|
26
|
+
export const DEFAULT_ROLE = process.env.GRIDLOCK_ROLE ?? "Prefill";
|
|
27
|
+
export const BENCHMARK_TOKENS = 32;
|
|
28
|
+
export const MAX_OUTPUT_TOKENS = 512;
|
|
29
|
+
export function wsUrl(httpBase) {
|
|
30
|
+
const base = httpBase.replace(/\/$/, "");
|
|
31
|
+
if (base.startsWith("https://"))
|
|
32
|
+
return base.replace("https://", "wss://") + "/v1/ws";
|
|
33
|
+
return base.replace("http://", "ws://") + "/v1/ws";
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isDashboardMode } from "./dashboard.js";
|
|
2
|
+
/** Log without breaking the live stdout dashboard (uses stderr in dashboard mode). */
|
|
3
|
+
export function workerLog(...args) {
|
|
4
|
+
if (isDashboardMode()) {
|
|
5
|
+
console.error(...args);
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
console.log(...args);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type ConnectionStatus = "starting" | "connected" | "disconnected" | "reconnecting";
|
|
2
|
+
export interface DashboardSnapshot {
|
|
3
|
+
wallet: string;
|
|
4
|
+
api: string;
|
|
5
|
+
hardware: string;
|
|
6
|
+
model: string;
|
|
7
|
+
inference: string;
|
|
8
|
+
benchmarkTokPerSec: number;
|
|
9
|
+
connection: ConnectionStatus;
|
|
10
|
+
workerStatus: string;
|
|
11
|
+
jobsCompleted: number;
|
|
12
|
+
jobsFailed: number;
|
|
13
|
+
jobsToday: number;
|
|
14
|
+
tokensTodayBase: number;
|
|
15
|
+
liveTokPerSec: number | null;
|
|
16
|
+
queueJobs: number | null;
|
|
17
|
+
inflightJobs: number | null;
|
|
18
|
+
workerInflightJobs: number | null;
|
|
19
|
+
currentJob: {
|
|
20
|
+
id: string;
|
|
21
|
+
tokens: number;
|
|
22
|
+
maxTokens: number;
|
|
23
|
+
startedAt: number;
|
|
24
|
+
} | null;
|
|
25
|
+
}
|
|
26
|
+
export interface LiveStatsPatch {
|
|
27
|
+
jobsToday: number;
|
|
28
|
+
tokensToday: number;
|
|
29
|
+
jobsFailedToday: number;
|
|
30
|
+
workerStatus: string;
|
|
31
|
+
wsTokPerSec: number;
|
|
32
|
+
queueJobs: number;
|
|
33
|
+
inflightJobs: number;
|
|
34
|
+
workerInflightJobs: number;
|
|
35
|
+
}
|
|
36
|
+
export interface DashboardOptions {
|
|
37
|
+
/** First terminal row for the dashboard box (1-based, below banner). */
|
|
38
|
+
anchorRow?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface WorkerDashboard {
|
|
41
|
+
update(patch: Partial<DashboardSnapshot>): void;
|
|
42
|
+
applyLiveStats(stats: LiveStatsPatch): void;
|
|
43
|
+
setJob(jobId: string, maxTokens: number): void;
|
|
44
|
+
setJobProgress(tokens: number, maxTokens?: number): void;
|
|
45
|
+
clearJob(jobId: string, success: boolean, tokens: number, elapsedMs: number): void;
|
|
46
|
+
setConnection(status: ConnectionStatus): void;
|
|
47
|
+
note(message: string): void;
|
|
48
|
+
start(): void;
|
|
49
|
+
stop(): void;
|
|
50
|
+
}
|
|
51
|
+
/** Interactive TTY dashboard — suppresses startup log lines. */
|
|
52
|
+
export declare function isDashboardMode(): boolean;
|
|
53
|
+
export declare function createDashboard(initial: DashboardSnapshot, options?: DashboardOptions): WorkerDashboard;
|
|
54
|
+
export declare function plainLog(msg: string): void;
|