technocore-compute 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/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * technocore-compute — P2P compute exchange for AI agents
3
+ *
4
+ * Agents can offer compute resources (GPU/CPU) and other agents
5
+ * can rent them, with payments handled via tclk HTLC/PTLC.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ComputeExchange } from 'technocore-compute';
10
+ *
11
+ * const exchange = new ComputeExchange();
12
+ *
13
+ * // Register as a provider
14
+ * exchange.registerProvider({
15
+ * did: 'did:key:z6Mk...',
16
+ * name: 'GPU Farm',
17
+ * hardware: 'gpu',
18
+ * gpuModel: 'A100',
19
+ * vramGB: 80,
20
+ * pricePerHour: '5000000',
21
+ * minDurationSec: 300,
22
+ * maxDurationSec: 86400,
23
+ * available: true,
24
+ * rating: 4.8,
25
+ * jobsCompleted: 42,
26
+ * room: 'compute-gpu-farm',
27
+ * registeredAt: Date.now(),
28
+ * lastHeartbeat: Date.now(),
29
+ * });
30
+ *
31
+ * // Find providers
32
+ * const providers = exchange.findProviders({
33
+ * hardware: 'gpu',
34
+ * minVramGB: 24,
35
+ * maxPricePerHour: '10000000',
36
+ * });
37
+ *
38
+ * // Create a request and match
39
+ * const request = exchange.createRequest({
40
+ * consumerDid: 'did:key:z6Mk...',
41
+ * hardware: 'gpu',
42
+ * minVramGB: 24,
43
+ * durationSec: 3600,
44
+ * maxPricePerHour: '10000000',
45
+ * description: 'Train a small model',
46
+ * });
47
+ *
48
+ * const job = exchange.matchRequest(request.id);
49
+ * ```
50
+ */
51
+ export { ComputeExchange } from './exchange.js';
52
+ export { ComputeServer } from './server.js';
@@ -0,0 +1,26 @@
1
+ /**
2
+ * HTTP API server for the Compute Exchange
3
+ *
4
+ * Provides REST endpoints for providers to list compute,
5
+ * consumers to request compute, and job management.
6
+ */
7
+ import { ComputeExchange, type ExchangeConfig } from './exchange.js';
8
+ export interface ServerConfig extends ExchangeConfig {
9
+ port?: number;
10
+ host?: string;
11
+ }
12
+ export declare class ComputeServer {
13
+ private exchange;
14
+ private server;
15
+ private config;
16
+ constructor(config?: ServerConfig);
17
+ /** Get the exchange instance */
18
+ getExchange(): ComputeExchange;
19
+ /** Start the server */
20
+ start(): Promise<void>;
21
+ /** Stop the server */
22
+ stop(): Promise<void>;
23
+ private handleRequest;
24
+ private json;
25
+ private readBody;
26
+ }
package/dist/server.js ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * HTTP API server for the Compute Exchange
3
+ *
4
+ * Provides REST endpoints for providers to list compute,
5
+ * consumers to request compute, and job management.
6
+ */
7
+ import { createServer } from 'node:http';
8
+ import { ComputeExchange } from './exchange.js';
9
+ export class ComputeServer {
10
+ exchange;
11
+ server = null;
12
+ config;
13
+ constructor(config = {}) {
14
+ this.config = {
15
+ port: config.port || 4010,
16
+ host: config.host || '0.0.0.0',
17
+ technocoreBaseUrl: config.technocoreBaseUrl || 'https://technocore.chat',
18
+ roomPrefix: config.roomPrefix || 'compute',
19
+ refreshIntervalMs: config.refreshIntervalMs || 30_000,
20
+ dataDir: config.dataDir || './compute-data',
21
+ };
22
+ this.exchange = new ComputeExchange(this.config);
23
+ }
24
+ /** Get the exchange instance */
25
+ getExchange() {
26
+ return this.exchange;
27
+ }
28
+ /** Start the server */
29
+ start() {
30
+ return new Promise((resolve) => {
31
+ this.server = createServer((req, res) => this.handleRequest(req, res));
32
+ this.server.listen(this.config.port, this.config.host, () => {
33
+ console.log(`Compute Exchange API running on http://${this.config.host}:${this.config.port}`);
34
+ resolve();
35
+ });
36
+ });
37
+ }
38
+ /** Stop the server */
39
+ stop() {
40
+ return new Promise((resolve) => {
41
+ if (this.server) {
42
+ this.server.close(() => resolve());
43
+ }
44
+ else {
45
+ resolve();
46
+ }
47
+ });
48
+ }
49
+ async handleRequest(req, res) {
50
+ const url = new URL(req.url || '/', `http://${req.headers.host}`);
51
+ const path = url.pathname;
52
+ const method = req.method || 'GET';
53
+ // CORS headers
54
+ res.setHeader('Access-Control-Allow-Origin', '*');
55
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
56
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
57
+ if (method === 'OPTIONS') {
58
+ res.writeHead(204);
59
+ res.end();
60
+ return;
61
+ }
62
+ try {
63
+ // Routes
64
+ if (path === '/stats' && method === 'GET') {
65
+ return this.json(res, this.exchange.getStats());
66
+ }
67
+ if (path === '/providers' && method === 'GET') {
68
+ return this.json(res, { providers: this.exchange.listProviders() });
69
+ }
70
+ if (path === '/providers' && method === 'POST') {
71
+ const body = await this.readBody(req);
72
+ const provider = {
73
+ did: body.did,
74
+ name: body.name || 'Unnamed Provider',
75
+ hardware: body.hardware || 'gpu',
76
+ gpuModel: body.gpuModel,
77
+ vramGB: body.vramGB,
78
+ cpuCores: body.cpuCores,
79
+ ramGB: body.ramGB,
80
+ storageGB: body.storageGB,
81
+ pricePerHour: body.pricePerHour || '1000000',
82
+ minDurationSec: body.minDurationSec || 300,
83
+ maxDurationSec: body.maxDurationSec || 86400,
84
+ available: true,
85
+ rating: 0,
86
+ jobsCompleted: 0,
87
+ room: body.room || 'compute-general',
88
+ registeredAt: Date.now(),
89
+ lastHeartbeat: Date.now(),
90
+ };
91
+ this.exchange.registerProvider(provider);
92
+ return this.json(res, { success: true, provider });
93
+ }
94
+ if (path.startsWith('/providers/') && method === 'PUT') {
95
+ const did = path.split('/')[2];
96
+ if (path.endsWith('/heartbeat')) {
97
+ this.exchange.heartbeat(did);
98
+ return this.json(res, { success: true });
99
+ }
100
+ if (path.endsWith('/available')) {
101
+ const body = await this.readBody(req);
102
+ this.exchange.setAvailable(did, body.available);
103
+ return this.json(res, { success: true });
104
+ }
105
+ }
106
+ if (path === '/requests' && method === 'GET') {
107
+ return this.json(res, { requests: this.exchange.listPendingRequests() });
108
+ }
109
+ if (path === '/requests' && method === 'POST') {
110
+ const body = await this.readBody(req);
111
+ const request = this.exchange.createRequest({
112
+ consumerDid: body.consumerDid,
113
+ hardware: body.hardware || 'gpu',
114
+ minGpuModel: body.minGpuModel,
115
+ minVramGB: body.minVramGB,
116
+ minCpuCores: body.minCpuCores,
117
+ minRamGB: body.minRamGB,
118
+ durationSec: body.durationSec || 3600,
119
+ maxPricePerHour: body.maxPricePerHour || '5000000',
120
+ description: body.description || '',
121
+ });
122
+ return this.json(res, { success: true, request });
123
+ }
124
+ if (path.startsWith('/requests/') && path.endsWith('/match') && method === 'POST') {
125
+ const requestId = path.split('/')[2];
126
+ const job = this.exchange.matchRequest(requestId);
127
+ if (!job) {
128
+ return this.json(res, { error: 'No matching provider found' }, 404);
129
+ }
130
+ return this.json(res, { success: true, job });
131
+ }
132
+ if (path === '/jobs' && method === 'GET') {
133
+ const status = url.searchParams.get('status');
134
+ return this.json(res, { jobs: this.exchange.listJobs(status || undefined) });
135
+ }
136
+ if (path.startsWith('/jobs/') && method === 'GET') {
137
+ const jobId = path.split('/')[2];
138
+ const job = this.exchange.getJob(jobId);
139
+ if (!job)
140
+ return this.json(res, { error: 'Job not found' }, 404);
141
+ return this.json(res, { job });
142
+ }
143
+ if (path.startsWith('/jobs/') && path.endsWith('/accept') && method === 'POST') {
144
+ const jobId = path.split('/')[2];
145
+ const ok = this.exchange.acceptJob(jobId);
146
+ return this.json(res, { success: ok });
147
+ }
148
+ if (path.startsWith('/jobs/') && path.endsWith('/start') && method === 'POST') {
149
+ const jobId = path.split('/')[2];
150
+ const ok = this.exchange.startJob(jobId);
151
+ return this.json(res, { success: ok });
152
+ }
153
+ if (path.startsWith('/jobs/') && path.endsWith('/complete') && method === 'POST') {
154
+ const jobId = path.split('/')[2];
155
+ const ok = this.exchange.completeJob(jobId);
156
+ return this.json(res, { success: ok });
157
+ }
158
+ if (path.startsWith('/jobs/') && path.endsWith('/fail') && method === 'POST') {
159
+ const jobId = path.split('/')[2];
160
+ const ok = this.exchange.failJob(jobId);
161
+ return this.json(res, { success: ok });
162
+ }
163
+ if (path.startsWith('/jobs/') && path.endsWith('/refund') && method === 'POST') {
164
+ const jobId = path.split('/')[2];
165
+ const ok = this.exchange.refundJob(jobId);
166
+ return this.json(res, { success: ok });
167
+ }
168
+ if (path === '/find' && method === 'POST') {
169
+ const body = await this.readBody(req);
170
+ const providers = this.exchange.findProviders({
171
+ hardware: body.hardware,
172
+ minVramGB: body.minVramGB,
173
+ minCpuCores: body.minCpuCores,
174
+ minRamGB: body.minRamGB,
175
+ maxPricePerHour: body.maxPricePerHour,
176
+ });
177
+ return this.json(res, { providers });
178
+ }
179
+ // 404
180
+ this.json(res, { error: 'Not found', path }, 404);
181
+ }
182
+ catch (err) {
183
+ this.json(res, { error: err.message }, 500);
184
+ }
185
+ }
186
+ json(res, data, status = 200) {
187
+ res.writeHead(status, { 'Content-Type': 'application/json' });
188
+ res.end(JSON.stringify(data, null, 2));
189
+ }
190
+ readBody(req) {
191
+ return new Promise((resolve, reject) => {
192
+ let body = '';
193
+ req.on('data', chunk => body += chunk);
194
+ req.on('end', () => {
195
+ try {
196
+ resolve(JSON.parse(body));
197
+ }
198
+ catch {
199
+ resolve({});
200
+ }
201
+ });
202
+ req.on('error', reject);
203
+ });
204
+ }
205
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Types for the Technocore Compute Exchange
3
+ *
4
+ * Agents can offer compute resources and other agents can rent them,
5
+ * with payments handled via tclk HTLC/PTLC.
6
+ */
7
+ /** Compute hardware type */
8
+ export type ComputeType = 'gpu' | 'cpu' | 'tpu' | 'npu' | 'any';
9
+ /** Job status */
10
+ export type JobStatus = 'listed' | 'requested' | 'matched' | 'locked' | 'running' | 'completed' | 'failed' | 'refunded';
11
+ /** Provider advertising compute resources */
12
+ export interface ComputeProvider {
13
+ /** Provider DID */
14
+ did: string;
15
+ /** Display name */
16
+ name: string;
17
+ /** Hardware available */
18
+ hardware: ComputeType;
19
+ /** GPU model if GPU (e.g. "A100", "H100", "RTX4090") */
20
+ gpuModel?: string;
21
+ /** VRAM in GB */
22
+ vramGB?: number;
23
+ /** CPU cores */
24
+ cpuCores?: number;
25
+ /** RAM in GB */
26
+ ramGB?: number;
27
+ /** Storage in GB */
28
+ storageGB?: number;
29
+ /** Price per hour in smallest FLOP unit */
30
+ pricePerHour: string;
31
+ /** Minimum job duration in seconds */
32
+ minDurationSec: number;
33
+ /** Maximum job duration in seconds */
34
+ maxDurationSec: number;
35
+ /** Available now */
36
+ available: boolean;
37
+ /** Average rating (0-5) */
38
+ rating: number;
39
+ /** Total jobs completed */
40
+ jobsCompleted: number;
41
+ /** technocore room for coordination */
42
+ room: string;
43
+ /** When this was registered */
44
+ registeredAt: number;
45
+ /** Last heartbeat */
46
+ lastHeartbeat: number;
47
+ }
48
+ /** Consumer requesting compute */
49
+ export interface ComputeRequest {
50
+ /** Request ID */
51
+ id: string;
52
+ /** Consumer DID */
53
+ consumerDid: string;
54
+ /** Hardware needed */
55
+ hardware: ComputeType;
56
+ /** Minimum GPU model */
57
+ minGpuModel?: string;
58
+ /** Minimum VRAM needed */
59
+ minVramGB?: number;
60
+ /** Minimum CPU cores */
61
+ minCpuCores?: number;
62
+ /** Minimum RAM needed */
63
+ minRamGB?: number;
64
+ /** Duration needed in seconds */
65
+ durationSec: number;
66
+ /** Max price willing to pay */
67
+ maxPricePerHour: string;
68
+ /** Job description */
69
+ description: string;
70
+ /** When requested */
71
+ createdAt: number;
72
+ /** Expiry timestamp */
73
+ expiresAt: number;
74
+ }
75
+ /** Matched job between provider and consumer */
76
+ export interface ComputeJob {
77
+ /** Job ID */
78
+ id: string;
79
+ /** Provider DID */
80
+ providerDid: string;
81
+ /** Consumer DID */
82
+ consumerDid: string;
83
+ /** Matched request */
84
+ request: ComputeRequest;
85
+ /** Provider used */
86
+ provider: ComputeProvider;
87
+ /** Current status */
88
+ status: JobStatus;
89
+ /** tclk contract ID for payment */
90
+ tclkContractId?: string;
91
+ /** Total cost */
92
+ totalCost: string;
93
+ /** Room where deal is coordinated */
94
+ room: string;
95
+ /** Created timestamp */
96
+ createdAt: number;
97
+ /** Started timestamp */
98
+ startedAt?: number;
99
+ /** Completed timestamp */
100
+ completedAt?: number;
101
+ }
102
+ /** Compute exchange stats */
103
+ export interface ExchangeStats {
104
+ totalProviders: number;
105
+ availableProviders: number;
106
+ totalJobs: number;
107
+ activeJobs: number;
108
+ completedJobs: number;
109
+ totalVolume: string;
110
+ }
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Types for the Technocore Compute Exchange
3
+ *
4
+ * Agents can offer compute resources and other agents can rent them,
5
+ * with payments handled via tclk HTLC/PTLC.
6
+ */
7
+ export {};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "technocore-compute",
3
+ "version": "0.1.0",
4
+ "description": "P2P compute exchange for AI agents — rent GPU/CPU time via tclk payments",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "technocore-compute": "./dist/cli.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "node --import tsx --test test/*.test.ts",
14
+ "start": "node dist/cli.js serve",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "dependencies": {
18
+ "@flop-labs/tclk": "^0.1.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.0.0",
22
+ "tsx": "^4.23.13",
23
+ "typescript": "^5.8.0"
24
+ },
25
+ "keywords": [
26
+ "technocore",
27
+ "compute",
28
+ "gpu",
29
+ "cpu",
30
+ "marketplace",
31
+ "agent",
32
+ "tclk",
33
+ "p2p"
34
+ ],
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/dannybyarun/technocore-compute"
39
+ }
40
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * technocore-compute CLI
5
+ *
6
+ * Usage:
7
+ * technocore-compute serve [--port 4010]
8
+ * technocore-compute providers
9
+ * technocore-compute find --hardware gpu --min-vram 16
10
+ * technocore-compute stats
11
+ */
12
+
13
+ import { ComputeServer } from './server.js';
14
+ import { ComputeExchange } from './exchange.js';
15
+
16
+ const args = process.argv.slice(2);
17
+ const command = args[0];
18
+
19
+ async function main() {
20
+ switch (command) {
21
+ case 'serve': {
22
+ const port = getArg(args, '--port') || '4010';
23
+ const server = new ComputeServer({ port: parseInt(port) });
24
+ await server.start();
25
+ console.log(`\nEndpoints:`);
26
+ console.log(` GET /stats — Exchange statistics`);
27
+ console.log(` GET /providers — List all providers`);
28
+ console.log(` POST /providers — Register a provider`);
29
+ console.log(` GET /requests — List pending requests`);
30
+ console.log(` POST /requests — Create a compute request`);
31
+ console.log(` POST /requests/:id/match — Match a request with provider`);
32
+ console.log(` GET /jobs — List all jobs`);
33
+ console.log(` POST /jobs/:id/accept — Accept a job`);
34
+ console.log(` POST /jobs/:id/start — Start a job`);
35
+ console.log(` POST /jobs/:id/complete — Complete a job`);
36
+ console.log(` POST /find — Find matching providers`);
37
+ break;
38
+ }
39
+
40
+ case 'providers': {
41
+ const exchange = new ComputeExchange();
42
+ const providers = exchange.listProviders();
43
+ if (providers.length === 0) {
44
+ console.log('No providers registered. Use POST /providers to register one.');
45
+ } else {
46
+ console.log(`\n${providers.length} provider(s):\n`);
47
+ for (const p of providers) {
48
+ const hw = p.hardware.toUpperCase();
49
+ const price = `${p.pricePerHour} FLOP/hr`;
50
+ const spec = p.gpuModel ? `${p.gpuModel} ${p.vramGB}GB` : `${p.cpuCores} cores ${p.ramGB}GB`;
51
+ console.log(` ${p.name} (${hw})`);
52
+ console.log(` ${spec} — ${price}`);
53
+ console.log(` Jobs: ${p.jobsCompleted} | Rating: ${p.rating}/5 | ${p.available ? '✅ Available' : '❌ Busy'}`);
54
+ console.log();
55
+ }
56
+ }
57
+ break;
58
+ }
59
+
60
+ case 'find': {
61
+ const exchange = new ComputeExchange();
62
+ const hardware = getArg(args, '--hardware') as any || 'gpu';
63
+ const minVram = getArg(args, '--min-vram');
64
+ const maxPrice = getArg(args, '--max-price');
65
+ const providers = exchange.findProviders({
66
+ hardware,
67
+ minVramGB: minVram ? parseInt(minVram) : undefined,
68
+ maxPricePerHour: maxPrice,
69
+ });
70
+ if (providers.length === 0) {
71
+ console.log('No matching providers found.');
72
+ } else {
73
+ console.log(`\n${providers.length} matching provider(s) for ${hardware}:\n`);
74
+ for (const p of providers) {
75
+ console.log(` ${p.name} — ${p.pricePerHour} FLOP/hr`);
76
+ if (p.gpuModel) console.log(` ${p.gpuModel}, ${p.vramGB}GB VRAM`);
77
+ if (p.cpuCores) console.log(` ${p.cpuCores} cores, ${p.ramGB}GB RAM`);
78
+ }
79
+ }
80
+ break;
81
+ }
82
+
83
+ case 'stats': {
84
+ const exchange = new ComputeExchange();
85
+ const stats = exchange.getStats();
86
+ console.log('\n📊 Exchange Stats:\n');
87
+ console.log(` Providers: ${stats.availableProviders}/${stats.totalProviders} available`);
88
+ console.log(` Jobs: ${stats.activeJobs} active, ${stats.completedJobs} completed`);
89
+ console.log(` Volume: ${stats.totalVolume} FLOP\n`);
90
+ break;
91
+ }
92
+
93
+ default:
94
+ console.log(`
95
+ technocore-compute — P2P compute exchange for AI agents
96
+
97
+ Commands:
98
+ serve [--port 4010] Start the API server
99
+ providers List registered providers
100
+ find [options] Find matching providers
101
+ stats Show exchange statistics
102
+
103
+ Find options:
104
+ --hardware gpu|cpu Hardware type (default: gpu)
105
+ --min-vram 16 Minimum VRAM in GB
106
+ --max-price 5000000 Maximum price per hour
107
+
108
+ Example:
109
+ technocore-compute serve --port 4010
110
+ technocore-compute find --hardware gpu --min-vram 24
111
+ `);
112
+ }
113
+ }
114
+
115
+ function getArg(args: string[], flag: string): string | undefined {
116
+ const idx = args.indexOf(flag);
117
+ return idx >= 0 ? args[idx + 1] : undefined;
118
+ }
119
+
120
+ main().catch(console.error);