@gns-foundation/hive-worker 0.1.0
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 +87 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +355 -0
- package/dist/cli.js.map +1 -0
- package/dist/dashboard.d.ts +25 -0
- package/dist/dashboard.js +97 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/executor.d.ts +16 -0
- package/dist/executor.js +201 -0
- package/dist/executor.js.map +1 -0
- package/dist/hardware.d.ts +19 -0
- package/dist/hardware.js +129 -0
- package/dist/hardware.js.map +1 -0
- package/dist/identity.d.ts +15 -0
- package/dist/identity.js +64 -0
- package/dist/identity.js.map +1 -0
- package/dist/jobs.d.ts +53 -0
- package/dist/jobs.js +133 -0
- package/dist/jobs.js.map +1 -0
- package/dist/llama.d.ts +12 -0
- package/dist/llama.js +65 -0
- package/dist/llama.js.map +1 -0
- package/dist/registry.d.ts +25 -0
- package/dist/registry.js +97 -0
- package/dist/registry.js.map +1 -0
- package/dist/settlement.d.ts +15 -0
- package/dist/settlement.js +112 -0
- package/dist/settlement.js.map +1 -0
- package/package.json +34 -0
- package/src/cli.ts +418 -0
- package/src/dashboard.ts +129 -0
- package/src/executor.ts +270 -0
- package/src/hardware.ts +137 -0
- package/src/identity.ts +82 -0
- package/src/jobs.ts +228 -0
- package/src/llama.ts +79 -0
- package/src/registry.ts +160 -0
- package/src/settlement.ts +145 -0
- package/tsconfig.json +16 -0
package/dist/executor.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// HIVE WORKER — EXECUTOR
|
|
3
|
+
// Runs llama-cli for an assigned job.
|
|
4
|
+
//
|
|
5
|
+
// Two modes:
|
|
6
|
+
// pipeline — rpc-server already running, orchestrator calls us
|
|
7
|
+
// (worker just tracks status, no local llama-cli)
|
|
8
|
+
// solo — worker claims and runs the whole model locally
|
|
9
|
+
// (for small models: phi-3-mini, gemma-2-2b, etc.)
|
|
10
|
+
//
|
|
11
|
+
// Solo mode is the active path for hive-worker v0.1 / v0.2.
|
|
12
|
+
// Pipeline mode is the full swarm path (Phase 3 whitepaper).
|
|
13
|
+
// ============================================================
|
|
14
|
+
import { spawn } from 'child_process';
|
|
15
|
+
import { execSync } from 'child_process';
|
|
16
|
+
import os from 'os';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
// ─── Binary detection ─────────────────────────────────────────
|
|
19
|
+
const LLAMA_CLI_CANDIDATES = [
|
|
20
|
+
'llama-cli',
|
|
21
|
+
'llama.cpp/llama-cli',
|
|
22
|
+
`${os.homedir()}/llama.cpp/llama-cli`,
|
|
23
|
+
`${os.homedir()}/llama.cpp/build/bin/llama-cli`,
|
|
24
|
+
`${os.homedir()}/llama.cpp/build/llama-cli`,
|
|
25
|
+
// Older name
|
|
26
|
+
'main',
|
|
27
|
+
`${os.homedir()}/llama.cpp/main`,
|
|
28
|
+
];
|
|
29
|
+
export function findLlamaCli() {
|
|
30
|
+
for (const candidate of LLAMA_CLI_CANDIDATES) {
|
|
31
|
+
try {
|
|
32
|
+
execSync(`test -f "${candidate}" || which "${candidate}" 2>/dev/null`, { timeout: 2000 });
|
|
33
|
+
return candidate;
|
|
34
|
+
}
|
|
35
|
+
catch { /* not found */ }
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// ─── Model cache ──────────────────────────────────────────────
|
|
40
|
+
const MODEL_CACHE_DIR = path.join(os.homedir(), '.hive', 'models');
|
|
41
|
+
import fs from 'fs';
|
|
42
|
+
export function ensureModelCacheDir() {
|
|
43
|
+
fs.mkdirSync(MODEL_CACHE_DIR, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
export function modelCachePath(modelId) {
|
|
46
|
+
// Normalize: "phi-3-mini" → "phi-3-mini.gguf"
|
|
47
|
+
const filename = modelId.endsWith('.gguf') ? modelId : `${modelId}.gguf`;
|
|
48
|
+
return path.join(MODEL_CACHE_DIR, filename);
|
|
49
|
+
}
|
|
50
|
+
export function isModelCached(modelId) {
|
|
51
|
+
return fs.existsSync(modelCachePath(modelId));
|
|
52
|
+
}
|
|
53
|
+
// Known small models with public GGUF URLs (Q4_K_M quantizations)
|
|
54
|
+
const KNOWN_MODELS = {
|
|
55
|
+
'phi-3-mini': 'https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-gguf/resolve/main/Phi-3-mini-4k-instruct-q4.gguf',
|
|
56
|
+
'gemma-2-2b': 'https://huggingface.co/bartowski/gemma-2-2b-it-GGUF/resolve/main/gemma-2-2b-it-Q4_K_M.gguf',
|
|
57
|
+
'tinyllama': 'https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf',
|
|
58
|
+
};
|
|
59
|
+
export function resolveModelUrl(job) {
|
|
60
|
+
if (job.model_url)
|
|
61
|
+
return job.model_url;
|
|
62
|
+
return KNOWN_MODELS[job.model_id] ?? null;
|
|
63
|
+
}
|
|
64
|
+
// ─── Download model (streaming, with progress) ───────────────
|
|
65
|
+
export async function downloadModel(modelId, url, onProgress) {
|
|
66
|
+
ensureModelCacheDir();
|
|
67
|
+
const dest = modelCachePath(modelId);
|
|
68
|
+
const tmpDest = dest + '.download';
|
|
69
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(300_000) });
|
|
70
|
+
if (!resp.ok)
|
|
71
|
+
throw new Error(`Model download failed: ${resp.status}`);
|
|
72
|
+
const totalBytes = parseInt(resp.headers.get('content-length') ?? '0', 10);
|
|
73
|
+
const totalMb = totalBytes / 1024 / 1024;
|
|
74
|
+
const writer = fs.createWriteStream(tmpDest);
|
|
75
|
+
let downloaded = 0;
|
|
76
|
+
if (!resp.body)
|
|
77
|
+
throw new Error('No response body');
|
|
78
|
+
const reader = resp.body.getReader();
|
|
79
|
+
while (true) {
|
|
80
|
+
const { done, value } = await reader.read();
|
|
81
|
+
if (done)
|
|
82
|
+
break;
|
|
83
|
+
writer.write(value);
|
|
84
|
+
downloaded += value.length;
|
|
85
|
+
if (totalBytes > 0) {
|
|
86
|
+
onProgress(Math.round((downloaded / totalBytes) * 100), Math.round(downloaded / 1024 / 1024), Math.round(totalMb));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
await new Promise((res, rej) => {
|
|
90
|
+
writer.end(() => res());
|
|
91
|
+
writer.on('error', rej);
|
|
92
|
+
});
|
|
93
|
+
fs.renameSync(tmpDest, dest);
|
|
94
|
+
return dest;
|
|
95
|
+
}
|
|
96
|
+
export async function executeJob(job, opts = {}) {
|
|
97
|
+
const llamaCli = findLlamaCli();
|
|
98
|
+
if (!llamaCli) {
|
|
99
|
+
throw new Error('llama-cli not found. Install llama.cpp: https://github.com/ggerganov/llama.cpp');
|
|
100
|
+
}
|
|
101
|
+
const modelPath = modelCachePath(job.model_id);
|
|
102
|
+
if (!fs.existsSync(modelPath)) {
|
|
103
|
+
throw new Error(`Model "${job.model_id}" not cached at ${modelPath}. ` +
|
|
104
|
+
`Run: hive-worker models fetch ${job.model_id}`);
|
|
105
|
+
}
|
|
106
|
+
return runLlamaCli(llamaCli, modelPath, job, opts);
|
|
107
|
+
}
|
|
108
|
+
function runLlamaCli(binary, modelPath, job, opts) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const startMs = Date.now();
|
|
111
|
+
// Build args
|
|
112
|
+
const args = [
|
|
113
|
+
'--model', modelPath,
|
|
114
|
+
'--prompt', job.prompt,
|
|
115
|
+
'--n-predict', String(job.max_tokens),
|
|
116
|
+
'--temp', String(job.temperature),
|
|
117
|
+
'--ctx-size', '4096',
|
|
118
|
+
'--threads', String(Math.max(1, Math.floor(os.cpus().length / 2))),
|
|
119
|
+
'--no-display-prompt', // suppress prompt echo
|
|
120
|
+
'--log-disable',
|
|
121
|
+
'--single-turn',
|
|
122
|
+
'-ngl', '0',
|
|
123
|
+
];
|
|
124
|
+
// Layer range hint (pipeline mode — rpc-server handles routing,
|
|
125
|
+
// but we pass the range so the model knows which layers to host)
|
|
126
|
+
if (job.layer_start !== 0 || job.layer_end !== 31) {
|
|
127
|
+
args.push('--n-gpu-layers', '0'); // CPU-only for partial layer ranges
|
|
128
|
+
}
|
|
129
|
+
// Apple Silicon: use Metal when running full model
|
|
130
|
+
const isApple = os.platform() === 'darwin' && os.arch() === 'arm64';
|
|
131
|
+
if (isApple && job.layer_start === 0) {
|
|
132
|
+
args.push('--n-gpu-layers', '99'); // offload all layers to Metal
|
|
133
|
+
}
|
|
134
|
+
opts.onLog?.(`Starting llama-cli for "${job.model_id}" [layers ${job.layer_start}–${job.layer_end}]`);
|
|
135
|
+
opts.onLog?.(`Command: ${binary} ${args.slice(0, 6).join(' ')} ...`);
|
|
136
|
+
const proc = spawn(binary, args, {
|
|
137
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
138
|
+
});
|
|
139
|
+
let output = '';
|
|
140
|
+
let stderrBuf = '';
|
|
141
|
+
// llama-cli writes generated tokens to stdout
|
|
142
|
+
proc.stdout.on('data', (chunk) => {
|
|
143
|
+
const text = chunk.toString();
|
|
144
|
+
output += text;
|
|
145
|
+
opts.onToken?.(text);
|
|
146
|
+
});
|
|
147
|
+
// Stats appear on stderr: "llama_print_timings: eval time = 12345 ms / 150 runs"
|
|
148
|
+
proc.stderr.on('data', (chunk) => {
|
|
149
|
+
stderrBuf += chunk.toString();
|
|
150
|
+
opts.onLog?.(chunk.toString().trim());
|
|
151
|
+
});
|
|
152
|
+
proc.on('error', (err) => {
|
|
153
|
+
reject(new Error(`llama-cli spawn error: ${err.message}`));
|
|
154
|
+
});
|
|
155
|
+
proc.on('close', (code) => {
|
|
156
|
+
const wallMs = Date.now() - startMs;
|
|
157
|
+
if (code !== 0) {
|
|
158
|
+
reject(new Error(`llama-cli exited with code ${code}. stderr: ${stderrBuf.slice(-500)}`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Parse tokens/sec from llama.cpp timing output
|
|
162
|
+
// Example: "llama_print_timings: eval time = 4523.11 ms / 150 runs"
|
|
163
|
+
const tpsMatch = stderrBuf.match(/eval time\s*=\s*([\d.]+)\s*ms\s*\/\s*(\d+)\s*runs/);
|
|
164
|
+
let tokensPerSecond = 0;
|
|
165
|
+
let tokensGenerated = output.split(/\s+/).length; // rough estimate
|
|
166
|
+
if (tpsMatch) {
|
|
167
|
+
const evalMs = parseFloat(tpsMatch[1]);
|
|
168
|
+
tokensGenerated = parseInt(tpsMatch[2], 10);
|
|
169
|
+
tokensPerSecond = Math.round((tokensGenerated / evalMs) * 1000 * 10) / 10;
|
|
170
|
+
}
|
|
171
|
+
else if (wallMs > 0) {
|
|
172
|
+
// Fallback: tokens from output word count / wall time
|
|
173
|
+
tokensPerSecond = Math.round((tokensGenerated / wallMs) * 1000 * 10) / 10;
|
|
174
|
+
}
|
|
175
|
+
resolve({
|
|
176
|
+
resultText: output.trim(),
|
|
177
|
+
tokensGenerated,
|
|
178
|
+
tokensPerSecond,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
// Job-level timeout (safety net on top of Supabase timeout_at)
|
|
182
|
+
const deadline = new Date(job.timeout_at).getTime();
|
|
183
|
+
const remaining = deadline - Date.now() - 10_000; // 10s buffer
|
|
184
|
+
if (remaining > 0) {
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
proc.kill('SIGTERM');
|
|
187
|
+
reject(new Error('Job timed out (executor deadline)'));
|
|
188
|
+
}, remaining);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// ─── List cached models ───────────────────────────────────────
|
|
193
|
+
export function listCachedModels() {
|
|
194
|
+
ensureModelCacheDir();
|
|
195
|
+
const files = fs.readdirSync(MODEL_CACHE_DIR).filter(f => f.endsWith('.gguf'));
|
|
196
|
+
return files.map(f => ({
|
|
197
|
+
modelId: f.replace('.gguf', ''),
|
|
198
|
+
sizeMb: Math.round(fs.statSync(path.join(MODEL_CACHE_DIR, f)).size / 1024 / 1024),
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface HardwareProfile {
|
|
2
|
+
cpuModel: string;
|
|
3
|
+
cpuCores: number;
|
|
4
|
+
ramGb: number;
|
|
5
|
+
platform: string;
|
|
6
|
+
arch: string;
|
|
7
|
+
gpuModel: string | null;
|
|
8
|
+
estimatedTflops: number;
|
|
9
|
+
hiveClass: 'phone' | 'laptop' | 'desktop' | 'server';
|
|
10
|
+
}
|
|
11
|
+
export interface GeoProfile {
|
|
12
|
+
h3Cell: string;
|
|
13
|
+
city: string;
|
|
14
|
+
country: string;
|
|
15
|
+
lat: number;
|
|
16
|
+
lng: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function detectHardware(): HardwareProfile;
|
|
19
|
+
export declare function detectGeo(): Promise<GeoProfile>;
|
package/dist/hardware.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// HIVE WORKER — HARDWARE
|
|
3
|
+
// Detect CPU, RAM, GPU, OS platform
|
|
4
|
+
// Derive H3 cell from IP geolocation (desktop has no GPS)
|
|
5
|
+
// ============================================================
|
|
6
|
+
import os from 'os';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import { latLngToCell } from 'h3-js';
|
|
9
|
+
// ─── CPU / RAM ───────────────────────────────────────────────
|
|
10
|
+
function detectGpu() {
|
|
11
|
+
try {
|
|
12
|
+
const plat = os.platform();
|
|
13
|
+
if (plat === 'darwin') {
|
|
14
|
+
const out = execSync('system_profiler SPDisplaysDataType 2>/dev/null | grep "Chipset Model"', {
|
|
15
|
+
encoding: 'utf-8', timeout: 3000,
|
|
16
|
+
});
|
|
17
|
+
const match = out.match(/Chipset Model:\s*(.+)/);
|
|
18
|
+
return match ? match[1].trim() : null;
|
|
19
|
+
}
|
|
20
|
+
if (plat === 'linux') {
|
|
21
|
+
try {
|
|
22
|
+
const out = execSync('nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null', {
|
|
23
|
+
encoding: 'utf-8', timeout: 3000,
|
|
24
|
+
});
|
|
25
|
+
return out.trim().split('\n')[0] || null;
|
|
26
|
+
}
|
|
27
|
+
catch { /* no nvidia */ }
|
|
28
|
+
try {
|
|
29
|
+
const out = execSync('rocm-smi --showproductname 2>/dev/null | grep "Card"', {
|
|
30
|
+
encoding: 'utf-8', timeout: 3000,
|
|
31
|
+
});
|
|
32
|
+
return out.trim() || null;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function estimateTflops(cpuCores, gpu, arch) {
|
|
45
|
+
// Very rough heuristic — enough for scheduling tier decisions
|
|
46
|
+
if (gpu) {
|
|
47
|
+
if (gpu.includes('A100'))
|
|
48
|
+
return 312;
|
|
49
|
+
if (gpu.includes('H100'))
|
|
50
|
+
return 756;
|
|
51
|
+
if (gpu.includes('4090'))
|
|
52
|
+
return 82;
|
|
53
|
+
if (gpu.includes('3090'))
|
|
54
|
+
return 35;
|
|
55
|
+
if (gpu.includes('RTX 5090'))
|
|
56
|
+
return 170;
|
|
57
|
+
if (gpu.includes('M4 Pro') || gpu.includes('M4 Max'))
|
|
58
|
+
return 14;
|
|
59
|
+
if (gpu.includes('M3 Pro') || gpu.includes('M3 Max'))
|
|
60
|
+
return 10;
|
|
61
|
+
if (gpu.includes('M2 Pro') || gpu.includes('M2 Max'))
|
|
62
|
+
return 6.5;
|
|
63
|
+
if (gpu.includes('M1 Pro') || gpu.includes('M1 Max'))
|
|
64
|
+
return 5.2;
|
|
65
|
+
if (gpu.includes('M4'))
|
|
66
|
+
return 4.6;
|
|
67
|
+
if (gpu.includes('M3'))
|
|
68
|
+
return 3.6;
|
|
69
|
+
if (gpu.includes('M2'))
|
|
70
|
+
return 2.6;
|
|
71
|
+
if (gpu.includes('M1'))
|
|
72
|
+
return 2.0;
|
|
73
|
+
}
|
|
74
|
+
// CPU-only estimate: ~0.05 TFLOPS per core for modern CPUs
|
|
75
|
+
return Math.round(cpuCores * 0.05 * 10) / 10;
|
|
76
|
+
}
|
|
77
|
+
function classifyDevice(ramGb, cpuCores, gpu) {
|
|
78
|
+
if (ramGb >= 64 && cpuCores >= 16)
|
|
79
|
+
return 'server';
|
|
80
|
+
if (ramGb >= 16 || (gpu && !gpu.toLowerCase().includes('apple')))
|
|
81
|
+
return 'desktop';
|
|
82
|
+
if (ramGb >= 8)
|
|
83
|
+
return 'laptop';
|
|
84
|
+
return 'phone';
|
|
85
|
+
}
|
|
86
|
+
export function detectHardware() {
|
|
87
|
+
const cpus = os.cpus();
|
|
88
|
+
const cpuModel = cpus[0]?.model?.trim() ?? 'Unknown CPU';
|
|
89
|
+
const cpuCores = cpus.length;
|
|
90
|
+
const ramGb = Math.round(os.totalmem() / (1024 ** 3));
|
|
91
|
+
const platform = os.platform();
|
|
92
|
+
const arch = os.arch();
|
|
93
|
+
const gpuModel = detectGpu();
|
|
94
|
+
const estimatedTflops = estimateTflops(cpuCores, gpuModel, arch);
|
|
95
|
+
const hiveClass = classifyDevice(ramGb, cpuCores, gpuModel);
|
|
96
|
+
return { cpuModel, cpuCores, ramGb, platform, arch, gpuModel, estimatedTflops, hiveClass };
|
|
97
|
+
}
|
|
98
|
+
// ─── GEO (IP-based, best effort) ─────────────────────────────
|
|
99
|
+
export async function detectGeo() {
|
|
100
|
+
try {
|
|
101
|
+
const resp = await fetch('https://ipapi.co/json/', { signal: AbortSignal.timeout(5000) });
|
|
102
|
+
if (!resp.ok)
|
|
103
|
+
throw new Error(`HTTP ${resp.status}`);
|
|
104
|
+
const data = await resp.json();
|
|
105
|
+
const lat = data.latitude ?? 0;
|
|
106
|
+
const lng = data.longitude ?? 0;
|
|
107
|
+
const h3Cell = latLngToCell(lat, lng, 6); // Res-6: ~36 km²
|
|
108
|
+
return {
|
|
109
|
+
h3Cell,
|
|
110
|
+
city: data.city ?? 'Unknown',
|
|
111
|
+
country: data.country_name ?? 'Unknown',
|
|
112
|
+
lat,
|
|
113
|
+
lng,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Fallback: Rome (GNS genesis location)
|
|
118
|
+
const lat = 41.8919;
|
|
119
|
+
const lng = 12.5113;
|
|
120
|
+
return {
|
|
121
|
+
h3Cell: latLngToCell(lat, lng, 6),
|
|
122
|
+
city: 'Unknown (geo offline)',
|
|
123
|
+
country: 'Unknown',
|
|
124
|
+
lat,
|
|
125
|
+
lng,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=hardware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hardware.js","sourceRoot":"","sources":["../src/hardware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface HiveIdentity {
|
|
2
|
+
pk: string;
|
|
3
|
+
sk: string;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function ensureHiveDir(): void;
|
|
7
|
+
export declare function generateIdentity(): HiveIdentity;
|
|
8
|
+
export declare function loadOrCreateIdentity(): {
|
|
9
|
+
identity: HiveIdentity;
|
|
10
|
+
isNew: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare function saveIdentity(identity: HiveIdentity): void;
|
|
13
|
+
export declare function sign(identity: HiveIdentity, message: string): string;
|
|
14
|
+
export declare function shortPk(pk: string): string;
|
|
15
|
+
export declare function identityPath(): string;
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// HIVE WORKER — IDENTITY
|
|
3
|
+
// Ed25519 keypair generation + local persistence
|
|
4
|
+
// ~/.hive/identity.json
|
|
5
|
+
// ============================================================
|
|
6
|
+
import nacl from 'tweetnacl';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
const HIVE_DIR = path.join(os.homedir(), '.hive');
|
|
11
|
+
const IDENTITY_FILE = path.join(HIVE_DIR, 'identity.json');
|
|
12
|
+
function bytesToHex(bytes) {
|
|
13
|
+
return Array.from(bytes)
|
|
14
|
+
.map(b => b.toString(16).padStart(2, '0'))
|
|
15
|
+
.join('');
|
|
16
|
+
}
|
|
17
|
+
function hexToBytes(hex) {
|
|
18
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
19
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
20
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
21
|
+
}
|
|
22
|
+
return bytes;
|
|
23
|
+
}
|
|
24
|
+
export function ensureHiveDir() {
|
|
25
|
+
if (!fs.existsSync(HIVE_DIR)) {
|
|
26
|
+
fs.mkdirSync(HIVE_DIR, { recursive: true, mode: 0o700 });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function generateIdentity() {
|
|
30
|
+
const keypair = nacl.sign.keyPair();
|
|
31
|
+
return {
|
|
32
|
+
pk: bytesToHex(keypair.publicKey),
|
|
33
|
+
sk: bytesToHex(keypair.secretKey),
|
|
34
|
+
createdAt: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function loadOrCreateIdentity() {
|
|
38
|
+
ensureHiveDir();
|
|
39
|
+
if (fs.existsSync(IDENTITY_FILE)) {
|
|
40
|
+
const raw = fs.readFileSync(IDENTITY_FILE, 'utf-8');
|
|
41
|
+
const identity = JSON.parse(raw);
|
|
42
|
+
return { identity, isNew: false };
|
|
43
|
+
}
|
|
44
|
+
const identity = generateIdentity();
|
|
45
|
+
fs.writeFileSync(IDENTITY_FILE, JSON.stringify(identity, null, 2), { mode: 0o600 });
|
|
46
|
+
return { identity, isNew: true };
|
|
47
|
+
}
|
|
48
|
+
export function saveIdentity(identity) {
|
|
49
|
+
ensureHiveDir();
|
|
50
|
+
fs.writeFileSync(IDENTITY_FILE, JSON.stringify(identity, null, 2), { mode: 0o600 });
|
|
51
|
+
}
|
|
52
|
+
export function sign(identity, message) {
|
|
53
|
+
const sk = hexToBytes(identity.sk);
|
|
54
|
+
const msgBytes = new TextEncoder().encode(message);
|
|
55
|
+
const sig = nacl.sign.detached(msgBytes, sk);
|
|
56
|
+
return bytesToHex(sig);
|
|
57
|
+
}
|
|
58
|
+
export function shortPk(pk) {
|
|
59
|
+
return pk.slice(0, 8);
|
|
60
|
+
}
|
|
61
|
+
export function identityPath() {
|
|
62
|
+
return IDENTITY_FILE;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
|
package/dist/jobs.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface HiveJob {
|
|
2
|
+
id: string;
|
|
3
|
+
h3_cell: string;
|
|
4
|
+
jurisdiction: string | null;
|
|
5
|
+
model_id: string;
|
|
6
|
+
model_url: string | null;
|
|
7
|
+
layer_start: number;
|
|
8
|
+
layer_end: number;
|
|
9
|
+
prompt: string;
|
|
10
|
+
max_tokens: number;
|
|
11
|
+
temperature: number;
|
|
12
|
+
status: 'pending' | 'assigned' | 'computing' | 'completed' | 'failed' | 'timed_out';
|
|
13
|
+
worker_pk: string | null;
|
|
14
|
+
assigned_at: string | null;
|
|
15
|
+
result_text: string | null;
|
|
16
|
+
tokens_generated: number | null;
|
|
17
|
+
tokens_per_second: number | null;
|
|
18
|
+
completed_at: string | null;
|
|
19
|
+
error_message: string | null;
|
|
20
|
+
gns_reward: number;
|
|
21
|
+
settled: boolean;
|
|
22
|
+
stellar_tx_hash: string | null;
|
|
23
|
+
submitter_pk: string;
|
|
24
|
+
created_at: string;
|
|
25
|
+
timeout_at: string;
|
|
26
|
+
}
|
|
27
|
+
export interface JobResult {
|
|
28
|
+
resultText: string;
|
|
29
|
+
tokensGenerated: number;
|
|
30
|
+
tokensPerSecond: number;
|
|
31
|
+
error?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function claimJob(workerPk: string, h3Cell: string, modelId?: string): Promise<HiveJob | null>;
|
|
34
|
+
export declare function markComputing(jobId: string): Promise<void>;
|
|
35
|
+
export declare function postResult(jobId: string, result: JobResult): Promise<void>;
|
|
36
|
+
export declare function postFailure(jobId: string, errorMsg: string): Promise<void>;
|
|
37
|
+
export declare function cleanupTimedOutJobs(): Promise<void>;
|
|
38
|
+
export declare function fetchJob(jobId: string): Promise<HiveJob | null>;
|
|
39
|
+
export declare function fetchRecentCompletedJobs(workerPk: string, limit?: number): Promise<HiveJob[]>;
|
|
40
|
+
export interface PollController {
|
|
41
|
+
stop: () => void;
|
|
42
|
+
isRunning: () => boolean;
|
|
43
|
+
}
|
|
44
|
+
export declare function startJobPoller(opts: {
|
|
45
|
+
workerPk: string;
|
|
46
|
+
h3Cell: string;
|
|
47
|
+
intervalMs: number;
|
|
48
|
+
onJobClaimed: (job: HiveJob) => void;
|
|
49
|
+
onJobCompleted: (job: HiveJob, result: JobResult) => void;
|
|
50
|
+
onJobFailed: (job: HiveJob, error: string) => void;
|
|
51
|
+
onLog: (msg: string) => void;
|
|
52
|
+
executor: (job: HiveJob) => Promise<JobResult>;
|
|
53
|
+
}): PollController;
|
package/dist/jobs.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// HIVE WORKER — JOB QUEUE
|
|
3
|
+
// Poll Supabase hive_jobs, claim atomically via FOR UPDATE
|
|
4
|
+
// SKIP LOCKED (Postgres handles races — no app-level locking needed)
|
|
5
|
+
// ============================================================
|
|
6
|
+
const SUPABASE_URL = 'https://kaqwkxfaclyqjlfhxrmt.supabase.co';
|
|
7
|
+
const SUPABASE_ANON = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImthcXdreGZhY2x5cWpsZmh4cm10Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI4MzU4NTAsImV4cCI6MjA4ODQxMTg1MH0.ClyWNGRxQjpKYzIROPZBqTXDsWvJioGe9pQymDOYBTc';
|
|
8
|
+
const HEADERS = {
|
|
9
|
+
'apikey': SUPABASE_ANON,
|
|
10
|
+
'Authorization': `Bearer ${SUPABASE_ANON}`,
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
};
|
|
13
|
+
// ─── Claim (atomic via Postgres RPC) ─────────────────────────
|
|
14
|
+
export async function claimJob(workerPk, h3Cell, modelId) {
|
|
15
|
+
const resp = await fetch(`${SUPABASE_URL}/rest/v1/rpc/claim_hive_job`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: HEADERS,
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
p_worker_pk: workerPk,
|
|
20
|
+
p_h3_cell: h3Cell,
|
|
21
|
+
p_model_id: modelId ?? null,
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
if (!resp.ok) {
|
|
25
|
+
const text = await resp.text();
|
|
26
|
+
throw new Error(`claimJob RPC failed: ${resp.status} ${text}`);
|
|
27
|
+
}
|
|
28
|
+
const rows = await resp.json();
|
|
29
|
+
return rows[0] ?? null;
|
|
30
|
+
}
|
|
31
|
+
// ─── Mark computing ───────────────────────────────────────────
|
|
32
|
+
export async function markComputing(jobId) {
|
|
33
|
+
await patchJob(jobId, { status: 'computing' });
|
|
34
|
+
}
|
|
35
|
+
// ─── Post result ──────────────────────────────────────────────
|
|
36
|
+
export async function postResult(jobId, result) {
|
|
37
|
+
await patchJob(jobId, {
|
|
38
|
+
status: 'completed',
|
|
39
|
+
result_text: result.resultText,
|
|
40
|
+
tokens_generated: result.tokensGenerated,
|
|
41
|
+
tokens_per_second: result.tokensPerSecond,
|
|
42
|
+
completed_at: new Date().toISOString(),
|
|
43
|
+
error_message: null,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// ─── Post failure ─────────────────────────────────────────────
|
|
47
|
+
export async function postFailure(jobId, errorMsg) {
|
|
48
|
+
await patchJob(jobId, {
|
|
49
|
+
status: 'failed',
|
|
50
|
+
error_message: errorMsg,
|
|
51
|
+
completed_at: new Date().toISOString(),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// ─── Trigger timeout cleanup (call once per poll cycle) ───────
|
|
55
|
+
export async function cleanupTimedOutJobs() {
|
|
56
|
+
await fetch(`${SUPABASE_URL}/rest/v1/rpc/timeout_stale_jobs`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: HEADERS,
|
|
59
|
+
body: JSON.stringify({}),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// ─── Fetch a specific job (for status watch) ──────────────────
|
|
63
|
+
export async function fetchJob(jobId) {
|
|
64
|
+
const resp = await fetch(`${SUPABASE_URL}/rest/v1/hive_jobs?id=eq.${jobId}&select=*`, { headers: HEADERS });
|
|
65
|
+
if (!resp.ok)
|
|
66
|
+
return null;
|
|
67
|
+
const rows = await resp.json();
|
|
68
|
+
return rows[0] ?? null;
|
|
69
|
+
}
|
|
70
|
+
// ─── Fetch recent completed jobs for this worker ──────────────
|
|
71
|
+
export async function fetchRecentCompletedJobs(workerPk, limit = 5) {
|
|
72
|
+
const resp = await fetch(`${SUPABASE_URL}/rest/v1/hive_jobs?worker_pk=eq.${workerPk}&status=eq.completed&order=completed_at.desc&limit=${limit}&select=*`, { headers: HEADERS });
|
|
73
|
+
if (!resp.ok)
|
|
74
|
+
return [];
|
|
75
|
+
return resp.json();
|
|
76
|
+
}
|
|
77
|
+
// ─── Patch helper ─────────────────────────────────────────────
|
|
78
|
+
async function patchJob(jobId, fields) {
|
|
79
|
+
const resp = await fetch(`${SUPABASE_URL}/rest/v1/hive_jobs?id=eq.${jobId}`, {
|
|
80
|
+
method: 'PATCH',
|
|
81
|
+
headers: { ...HEADERS, 'Prefer': 'return=minimal' },
|
|
82
|
+
body: JSON.stringify(fields),
|
|
83
|
+
});
|
|
84
|
+
if (!resp.ok && resp.status !== 204) {
|
|
85
|
+
const text = await resp.text();
|
|
86
|
+
throw new Error(`patchJob failed: ${resp.status} ${text}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
export function startJobPoller(opts) {
|
|
90
|
+
let running = true;
|
|
91
|
+
let busy = false;
|
|
92
|
+
const tick = async () => {
|
|
93
|
+
if (!running || busy)
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
// Run cleanup once per cycle
|
|
97
|
+
await cleanupTimedOutJobs().catch(() => { });
|
|
98
|
+
const job = await claimJob(opts.workerPk, opts.h3Cell);
|
|
99
|
+
if (!job)
|
|
100
|
+
return;
|
|
101
|
+
// Got one
|
|
102
|
+
busy = true;
|
|
103
|
+
opts.onJobClaimed(job);
|
|
104
|
+
try {
|
|
105
|
+
await markComputing(job.id);
|
|
106
|
+
const result = await opts.executor(job);
|
|
107
|
+
await postResult(job.id, result);
|
|
108
|
+
opts.onJobCompleted(job, result);
|
|
109
|
+
}
|
|
110
|
+
catch (execErr) {
|
|
111
|
+
const errMsg = execErr instanceof Error ? execErr.message : String(execErr);
|
|
112
|
+
await postFailure(job.id, errMsg).catch(() => { });
|
|
113
|
+
opts.onJobFailed(job, errMsg);
|
|
114
|
+
opts.onLog(`Job ${job.id.slice(0, 8)} failed: ${errMsg}`);
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
busy = false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (pollErr) {
|
|
121
|
+
opts.onLog(`Poll error: ${pollErr instanceof Error ? pollErr.message : String(pollErr)}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const timer = setInterval(tick, opts.intervalMs);
|
|
125
|
+
return {
|
|
126
|
+
stop: () => {
|
|
127
|
+
running = false;
|
|
128
|
+
clearInterval(timer);
|
|
129
|
+
},
|
|
130
|
+
isRunning: () => running,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=jobs.js.map
|
package/dist/jobs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jobs.js","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"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"}
|