lightnode-sdk 0.7.5 → 0.7.7
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/cli.js +33 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/onchain.d.ts +11 -4
- package/dist/onchain.js +54 -4
- package/dist/worker-operator.d.ts +13 -1
- package/dist/worker-operator.js +26 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -49,6 +49,7 @@ Worker operator (needs PRIVATE_KEY in env; signs as the worker key):
|
|
|
49
49
|
worker preflight run one real test inference, print verdict + timings
|
|
50
50
|
([--key 0x...] [--model llama3-8b] [--deadline 60])
|
|
51
51
|
worker status [addr] registration, stake, claimable, live protocol config
|
|
52
|
+
worker models <addr> models served, reconciled vs chain (servingNow truth)
|
|
52
53
|
worker can-deregister check what blocks the exit (in-flight jobs), no spend
|
|
53
54
|
worker settle release completed jobs past their window + withdraw
|
|
54
55
|
worker clearstuck claimTimeout acked, past-deadline jobs (unblocks exit)
|
|
@@ -313,10 +314,38 @@ async function main() {
|
|
|
313
314
|
}
|
|
314
315
|
break;
|
|
315
316
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
317
|
+
if (sub === "models") {
|
|
318
|
+
// The models a worker serves, reconciled against the chain (read-only,
|
|
319
|
+
// no key). onchainEligible is the truth; indexedActive is the subgraph's
|
|
320
|
+
// (which goes stale after a deregister/re-register).
|
|
321
|
+
const addr = positionals[2] ?? die("usage: lightnode worker models <address> [--net testnet]");
|
|
322
|
+
const served = await ln.getServedModels(addr);
|
|
323
|
+
console.log(JSON.stringify(served.map((m) => ({
|
|
324
|
+
model: m.name ?? m.modelId,
|
|
325
|
+
servingNow: m.onchainEligible, // true | false | null (chain unavailable)
|
|
326
|
+
indexedActive: m.indexedActive,
|
|
327
|
+
feeLcai: m.feeWei ? Number(BigInt(m.feeWei)) / 1e18 : null,
|
|
328
|
+
maxOutputTokens: m.maxOutputTokens ?? null,
|
|
329
|
+
})), null, 2));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
// Default: one-shot worker summary by address. Registration is read straight
|
|
333
|
+
// from the chain (isRegistered); served models are reconciled against the
|
|
334
|
+
// chain via getServedModels (onchainEligible), so a stale index row can't
|
|
335
|
+
// misreport what the worker actually serves.
|
|
336
|
+
const addr = sub ?? die("usage: lightnode worker <address|watch|preflight|status|models|can-deregister|settle|clearstuck|withdraw|deregister> [...]");
|
|
337
|
+
const [w, registered, jobs, served] = await Promise.all([
|
|
338
|
+
ln.getWorker(addr),
|
|
339
|
+
ln.isRegistered(addr),
|
|
340
|
+
ln.getWorkerJobs(addr, 5),
|
|
341
|
+
ln.getServedModels(addr).catch(() => []),
|
|
342
|
+
]);
|
|
343
|
+
console.log(JSON.stringify({
|
|
344
|
+
onchainRegistered: registered,
|
|
345
|
+
servingModels: served.filter((m) => m.onchainEligible === true).map((m) => m.name ?? m.modelId),
|
|
346
|
+
worker: w,
|
|
347
|
+
recentJobs: jobs.map((j) => ({ id: j.id, state: j.state })),
|
|
348
|
+
}, null, 2));
|
|
320
349
|
break;
|
|
321
350
|
}
|
|
322
351
|
case "job": {
|
package/dist/index.d.ts
CHANGED
|
@@ -133,7 +133,7 @@ export declare class LightNode {
|
|
|
133
133
|
* (especially in registry-proxy environments like StackBlitz where lockfiles
|
|
134
134
|
* may pin an older minor than the local install command suggests).
|
|
135
135
|
*/
|
|
136
|
-
export declare const SDK_VERSION = "0.7.
|
|
136
|
+
export declare const SDK_VERSION = "0.7.7";
|
|
137
137
|
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, resolveJobTransactions, fetchWorkerModels, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, runInferenceWithKey, runInferenceStream, Conversation, chat, runInferenceBatch, Agent, parseAgentOutput, workerPreflight, workerWatch, Bridge, BRIDGE_ROUTE, HYPERLANE_ROUTER_ABI, ERC20_ABI, addressToBytes32, quoteBridgeFee, bridgeableBalance, bridgeAllowance, approveBridge, bridgeTransfer, DAO, DAO_ADDRESSES, ProposalState, PROPOSAL_STATE_LABEL, VoteSupport, GOVERNOR_ABI, VOTES_ABI, OnchainModelRegistry, AIVM_MODEL_REGISTRY_ABI, BENCHMARK_REGISTRY_ABI, ModelStatus, MODEL_STATUS_LABEL, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, WorkerOperator, WORKER_REGISTRY_ABI, JOB_REGISTRY_OPERATOR_ABI, AI_CONFIG_ABI, JOB_STATE, decodeWorkerError, WorkerOpError, isWorkerOpError, };
|
|
138
138
|
export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
|
|
139
139
|
export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult } from "./inference.js";
|
package/dist/index.js
CHANGED
|
@@ -212,7 +212,7 @@ export class LightNode {
|
|
|
212
212
|
* (especially in registry-proxy environments like StackBlitz where lockfiles
|
|
213
213
|
* may pin an older minor than the local install command suggests).
|
|
214
214
|
*/
|
|
215
|
-
export const SDK_VERSION = "0.7.
|
|
215
|
+
export const SDK_VERSION = "0.7.7";
|
|
216
216
|
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei,
|
|
217
217
|
// v0.7.3 per-job transaction-hash resolver (lifts the upstream
|
|
218
218
|
// subgraph's "block-only" Job entity to a deep-linkable Job + tx pair).
|
package/dist/onchain.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { NetworkConfig } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
* Authoritative worker registration
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* Authoritative worker registration from the chain. Prefers a direct
|
|
4
|
+
* WorkerRegistry.isWorkerRegistered() eth_call (instant, current state); falls
|
|
5
|
+
* back to scanning the join/exit event log if that read is unavailable. Both are
|
|
6
|
+
* independent of the public indexer, which can lag a deregister -> re-register
|
|
7
|
+
* cycle. Returns true/false, or null when the chain can't answer.
|
|
7
8
|
*/
|
|
8
9
|
export declare function isRegistered(cfg: NetworkConfig, address: string): Promise<boolean | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Registration from the WorkerRegistry join/exit event log - the fallback when
|
|
12
|
+
* the direct read is unavailable. Takes the latest of the worker's join/exit
|
|
13
|
+
* events; null when the chain can't answer or there are no events for it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isRegisteredFromEvents(cfg: NetworkConfig, address: string): Promise<boolean | null>;
|
|
9
16
|
/**
|
|
10
17
|
* On-chain truth for which of `modelIds` a worker currently serves, via
|
|
11
18
|
* WorkerRegistry.isEligible(worker, modelId). Stronger than the subgraph's
|
package/dist/onchain.js
CHANGED
|
@@ -2,13 +2,63 @@ import { REGISTRY_TOPICS } from "./networks.js";
|
|
|
2
2
|
function addressTopic(address) {
|
|
3
3
|
return "0x" + address.toLowerCase().replace(/^0x/, "").padStart(64, "0");
|
|
4
4
|
}
|
|
5
|
+
// WorkerRegistry.isWorkerRegistered(address) selector. Unlike most of the
|
|
6
|
+
// predeploy's getters this view does NOT revert, and it reflects current state
|
|
7
|
+
// instantly - so it never lags a register/deregister the way the event log can
|
|
8
|
+
// when several happen in quick succession.
|
|
9
|
+
const IS_WORKER_REGISTERED_SELECTOR = "0xe798a7da";
|
|
5
10
|
/**
|
|
6
|
-
* Authoritative worker registration
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
11
|
+
* Authoritative worker registration from the chain. Prefers a direct
|
|
12
|
+
* WorkerRegistry.isWorkerRegistered() eth_call (instant, current state); falls
|
|
13
|
+
* back to scanning the join/exit event log if that read is unavailable. Both are
|
|
14
|
+
* independent of the public indexer, which can lag a deregister -> re-register
|
|
15
|
+
* cycle. Returns true/false, or null when the chain can't answer.
|
|
10
16
|
*/
|
|
11
17
|
export async function isRegistered(cfg, address) {
|
|
18
|
+
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
|
|
19
|
+
return null;
|
|
20
|
+
const direct = await isRegisteredDirect(cfg, address);
|
|
21
|
+
if (direct !== null)
|
|
22
|
+
return direct;
|
|
23
|
+
return isRegisteredFromEvents(cfg, address);
|
|
24
|
+
}
|
|
25
|
+
/** Direct contract read - the preferred, lag-free path. null on any failure. */
|
|
26
|
+
async function isRegisteredDirect(cfg, address) {
|
|
27
|
+
const ctrl = new AbortController();
|
|
28
|
+
const timer = setTimeout(() => ctrl.abort(), 8000);
|
|
29
|
+
try {
|
|
30
|
+
const data = `${IS_WORKER_REGISTERED_SELECTOR}${address.toLowerCase().replace(/^0x/, "").padStart(64, "0")}`;
|
|
31
|
+
const res = await fetch(cfg.rpc, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "content-type": "application/json" },
|
|
34
|
+
body: JSON.stringify({
|
|
35
|
+
jsonrpc: "2.0",
|
|
36
|
+
id: 1,
|
|
37
|
+
method: "eth_call",
|
|
38
|
+
params: [{ to: cfg.workerRegistry, data }, "latest"],
|
|
39
|
+
}),
|
|
40
|
+
signal: ctrl.signal,
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
return null;
|
|
44
|
+
const json = (await res.json());
|
|
45
|
+
if (json.error || typeof json.result !== "string")
|
|
46
|
+
return null;
|
|
47
|
+
return /0*1$/.test(json.result.replace(/^0x/, ""));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Registration from the WorkerRegistry join/exit event log - the fallback when
|
|
58
|
+
* the direct read is unavailable. Takes the latest of the worker's join/exit
|
|
59
|
+
* events; null when the chain can't answer or there are no events for it.
|
|
60
|
+
*/
|
|
61
|
+
export async function isRegisteredFromEvents(cfg, address) {
|
|
12
62
|
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
|
|
13
63
|
return null;
|
|
14
64
|
const ctrl = new AbortController();
|
|
@@ -210,9 +210,10 @@ export declare class WorkerOperator {
|
|
|
210
210
|
readonly network: NetworkConfig;
|
|
211
211
|
private readonly pub;
|
|
212
212
|
private readonly wallet?;
|
|
213
|
-
private readonly
|
|
213
|
+
private readonly maybeAddr;
|
|
214
214
|
private cfgCache?;
|
|
215
215
|
constructor(network: NetworkId | NetworkConfig, opts: WorkerOperatorOpts);
|
|
216
|
+
private get addr();
|
|
216
217
|
private requireWallet;
|
|
217
218
|
private get jobReg();
|
|
218
219
|
private get workerReg();
|
|
@@ -282,6 +283,17 @@ export declare class WorkerOperator {
|
|
|
282
283
|
withdraw(): Promise<`0x${string}`>;
|
|
283
284
|
/** Deregister - releases stake to the wallet. Reverts (ActiveJobsExist) if any in-flight job remains. */
|
|
284
285
|
deregister(): Promise<`0x${string}`>;
|
|
286
|
+
/**
|
|
287
|
+
* Add a supported model to THIS (already-registered) worker on-chain. Accepts a
|
|
288
|
+
* model tag (e.g. "gemma4:e2b") or a raw bytes32 modelId.
|
|
289
|
+
*
|
|
290
|
+
* This is the gas-correct version of the step the worker daemon's one-shot
|
|
291
|
+
* register botches: the daemon sends addSupportedModel with an under-set gas
|
|
292
|
+
* limit, so it OutOfGas-reverts (and its rollback deregister can too). viem
|
|
293
|
+
* estimates the gas here, so it lands. Use it to finish a worker that staked but
|
|
294
|
+
* failed to add its model. No-op (returns null) if already serving the model.
|
|
295
|
+
*/
|
|
296
|
+
addModel(modelTagOrId: string): Promise<`0x${string}` | null>;
|
|
285
297
|
/**
|
|
286
298
|
* The flagship rescue: clear stuck jobs then release any settled completed jobs +
|
|
287
299
|
* withdraw earnings then deregister. The one flow no official tool provides.
|
package/dist/worker-operator.js
CHANGED
|
@@ -287,9 +287,13 @@ export class WorkerOperator {
|
|
|
287
287
|
const acct = opts.walletClient?.account;
|
|
288
288
|
const fromWallet = typeof acct === "string" ? acct : acct?.address;
|
|
289
289
|
const a = (opts.workerAddress ?? fromWallet);
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
this.maybeAddr = a ? a.toLowerCase() : undefined;
|
|
291
|
+
}
|
|
292
|
+
get addr() {
|
|
293
|
+
if (!this.maybeAddr) {
|
|
294
|
+
throw new Error("WorkerOperator: this method needs the worker address. Pass `workerAddress` (or a `walletClient` with an account) when constructing WorkerOperator.");
|
|
295
|
+
}
|
|
296
|
+
return this.maybeAddr;
|
|
293
297
|
}
|
|
294
298
|
requireWallet(op) {
|
|
295
299
|
if (!this.wallet)
|
|
@@ -525,6 +529,25 @@ export class WorkerOperator {
|
|
|
525
529
|
async deregister() {
|
|
526
530
|
return this.send("deregister", this.workerReg, WORKER_REGISTRY_ABI_PARSED, "deregisterWorker", []);
|
|
527
531
|
}
|
|
532
|
+
/**
|
|
533
|
+
* Add a supported model to THIS (already-registered) worker on-chain. Accepts a
|
|
534
|
+
* model tag (e.g. "gemma4:e2b") or a raw bytes32 modelId.
|
|
535
|
+
*
|
|
536
|
+
* This is the gas-correct version of the step the worker daemon's one-shot
|
|
537
|
+
* register botches: the daemon sends addSupportedModel with an under-set gas
|
|
538
|
+
* limit, so it OutOfGas-reverts (and its rollback deregister can too). viem
|
|
539
|
+
* estimates the gas here, so it lands. Use it to finish a worker that staked but
|
|
540
|
+
* failed to add its model. No-op (returns null) if already serving the model.
|
|
541
|
+
*/
|
|
542
|
+
async addModel(modelTagOrId) {
|
|
543
|
+
const id = modelTagOrId.startsWith("0x") && modelTagOrId.length === 66
|
|
544
|
+
? modelTagOrId.toLowerCase()
|
|
545
|
+
: (await import("./inference.js")).modelId(modelTagOrId);
|
|
546
|
+
const already = (await this.read(this.workerReg, WORKER_REGISTRY_ABI_PARSED, "isEligible", [this.addr, id]));
|
|
547
|
+
if (already)
|
|
548
|
+
return null;
|
|
549
|
+
return this.send("addModel", this.workerReg, WORKER_REGISTRY_ABI_PARSED, "addSupportedModel", [id]);
|
|
550
|
+
}
|
|
528
551
|
/**
|
|
529
552
|
* The flagship rescue: clear stuck jobs then release any settled completed jobs +
|
|
530
553
|
* withdraw earnings then deregister. The one flow no official tool provides.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightnode-sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"description": "Read-only TypeScript client for LightChain AI: workers, jobs, models, on-chain registration, and per-model network analytics. Independent, community-built (not an official LightChain package).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|