lightnode-sdk 0.3.1 → 0.4.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 +38 -0
- package/dist/add.d.ts +51 -0
- package/dist/add.js +935 -0
- package/dist/cli.js +87 -8
- package/dist/errors.d.ts +55 -0
- package/dist/errors.js +64 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +5 -2
- package/dist/inference.d.ts +130 -0
- package/dist/inference.js +293 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { LightNode, modelStatsCsv, workerStatsCsv, workerJobsCsv } from "./index.js";
|
|
3
|
+
import { addInference, addAnalyticsDashboard, addNftMint, addChat } from "./add.js";
|
|
3
4
|
function flag(name) {
|
|
4
5
|
const i = process.argv.indexOf(name);
|
|
5
6
|
return i >= 0 ? process.argv[i + 1] : undefined;
|
|
@@ -16,14 +17,22 @@ const lcai = (wei) => (wei ? Number(BigInt(wei)) / 1e18 : 0);
|
|
|
16
17
|
const rate = (r) => (r == null ? "-" : `${Math.round(r * 100)}%`);
|
|
17
18
|
const HELP = `lightnode <command> [--net mainnet|testnet]
|
|
18
19
|
|
|
19
|
-
network
|
|
20
|
-
models
|
|
21
|
-
worker <addr>
|
|
22
|
-
jobs <addr> [--csv]
|
|
23
|
-
registered <addr>
|
|
24
|
-
fee [model]
|
|
25
|
-
analytics [--csv]
|
|
26
|
-
reliability [--csv]
|
|
20
|
+
network network summary (workers, jobs, models, earnings)
|
|
21
|
+
models registered models + per-job fee
|
|
22
|
+
worker <addr> a worker: on-chain registration + recent jobs
|
|
23
|
+
jobs <addr> [--csv] one worker's job history (table or CSV)
|
|
24
|
+
registered <addr> true | false | null (read from chain events)
|
|
25
|
+
fee [model] on-chain inference fee (default llama3-8b)
|
|
26
|
+
analytics [--csv] per-model performance (completion, p50/p95, incomplete)
|
|
27
|
+
reliability [--csv] per-worker reliability, busiest first
|
|
28
|
+
|
|
29
|
+
add inference end-to-end encrypted inference route/script
|
|
30
|
+
add chat chat-style UI with conversation history
|
|
31
|
+
add analytics-dashboard read-only network + worker analytics page
|
|
32
|
+
add nft-mint-with-inference AI-generated NFT metadata (provenance on-chain)
|
|
33
|
+
(all add commands: [--template auto|nextjs-api|hono|node] [--force])
|
|
34
|
+
|
|
35
|
+
To scaffold a new project instead, run: npm create lightnode-app my-app`;
|
|
27
36
|
async function main() {
|
|
28
37
|
const ln = new LightNode(net);
|
|
29
38
|
switch (cmd) {
|
|
@@ -89,6 +98,76 @@ async function main() {
|
|
|
89
98
|
}
|
|
90
99
|
break;
|
|
91
100
|
}
|
|
101
|
+
case "add": {
|
|
102
|
+
const sub = positionals[1];
|
|
103
|
+
const template = flag("--template") ?? "auto";
|
|
104
|
+
const force = process.argv.includes("--force");
|
|
105
|
+
const network = (net === "mainnet" ? "mainnet" : "testnet");
|
|
106
|
+
const known = ["inference", "chat", "analytics-dashboard", "nft-mint-with-inference"];
|
|
107
|
+
if (!known.includes(sub ?? "")) {
|
|
108
|
+
die(`usage: lightnode add <${known.join("|")}> [--template auto|nextjs-api|hono|node] [--net testnet|mainnet] [--force]`);
|
|
109
|
+
}
|
|
110
|
+
const result = sub === "analytics-dashboard"
|
|
111
|
+
? addAnalyticsDashboard({ template, network, force })
|
|
112
|
+
: sub === "nft-mint-with-inference"
|
|
113
|
+
? addNftMint({ template, network, force })
|
|
114
|
+
: sub === "chat"
|
|
115
|
+
? addChat({ template, network, force })
|
|
116
|
+
: addInference({ template, network, force });
|
|
117
|
+
console.log(`▶ add ${sub} (${result.template} template, default network ${result.network})`);
|
|
118
|
+
for (const f of result.written) {
|
|
119
|
+
if (f.skipped)
|
|
120
|
+
console.log(` ⤴ ${f.path} (skipped - ${f.reason})`);
|
|
121
|
+
else
|
|
122
|
+
console.log(` ✓ ${f.path}`);
|
|
123
|
+
}
|
|
124
|
+
const anyWritten = result.written.some((f) => !f.skipped);
|
|
125
|
+
if (!anyWritten) {
|
|
126
|
+
console.log("\nNothing to do - all target files already exist. Pass --force to overwrite.");
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(`\nNext steps:`);
|
|
130
|
+
console.log(` 1. ${result.install}`);
|
|
131
|
+
if (sub === "nft-mint-with-inference" || sub === "inference" || sub === "chat") {
|
|
132
|
+
console.log(` 2. cp .env.example .env (and put a funded ${result.network} PRIVATE_KEY in it)`);
|
|
133
|
+
if (sub === "chat" && result.template === "nextjs-api") {
|
|
134
|
+
console.log(` 3. Make sure /api/inference is mounted too (run: npx lightnode add inference)`);
|
|
135
|
+
console.log(` 4. npm run dev, open /chat`);
|
|
136
|
+
}
|
|
137
|
+
else if (sub === "chat") {
|
|
138
|
+
console.log(` 3. tsx chat-repl.ts (interactive terminal chat)`);
|
|
139
|
+
}
|
|
140
|
+
else if (sub === "nft-mint-with-inference" && result.template === "nextjs-api") {
|
|
141
|
+
console.log(` 3. Make sure /api/inference is mounted too (run: npx lightnode add inference)`);
|
|
142
|
+
console.log(` 4. npm run dev, open /nft-mint`);
|
|
143
|
+
}
|
|
144
|
+
else if (result.template === "nextjs-api") {
|
|
145
|
+
console.log(` 3. npm run dev (then POST /api/inference)`);
|
|
146
|
+
}
|
|
147
|
+
else if (result.template === "hono") {
|
|
148
|
+
console.log(` 3. wire inferenceHandler into your Hono app, then start it`);
|
|
149
|
+
}
|
|
150
|
+
else if (sub === "nft-mint-with-inference") {
|
|
151
|
+
console.log(` 3. tsx nft-metadata.ts "My NFT" "concept goes here"`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log(` 3. tsx lightchain-inference.ts "your prompt"`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// analytics-dashboard - read-only, no private key needed.
|
|
159
|
+
if (result.template === "nextjs-api") {
|
|
160
|
+
console.log(` 2. npm run dev, open /lightnode-analytics`);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
console.log(` 2. tsx lightnode-analytics.ts`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
console.log(`\nFree testnet LCAI: https://lightfaucet.ai`);
|
|
167
|
+
console.log(`Builder docs: https://lightnode.app/build`);
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
92
171
|
default:
|
|
93
172
|
console.log(HELP);
|
|
94
173
|
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors thrown by the high-level helpers (`runInference`, gateway calls
|
|
3
|
+
* inside `prepareSession`, etc.). Catching by class lets callers branch on the
|
|
4
|
+
* failure mode cleanly instead of regexing message strings.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The dispatcher picked a worker and the on-chain `submitJob` succeeded, but the
|
|
8
|
+
* worker never emitted `JobCompleted` inside the deadline. The protocol times
|
|
9
|
+
* out and refunds the escrowed fee after its dispute window (a few hours on
|
|
10
|
+
* testnet, ~24h on mainnet); the consumer does not need to call any timeoutJob.
|
|
11
|
+
*
|
|
12
|
+
* Re-running creates a NEW session with a different worker - the assignment is
|
|
13
|
+
* stochastic, so a retry almost always lands on a healthy one.
|
|
14
|
+
*/
|
|
15
|
+
export declare class StalledWorkerError extends Error {
|
|
16
|
+
readonly jobId: bigint;
|
|
17
|
+
readonly worker: `0x${string}`;
|
|
18
|
+
readonly submitTx: `0x${string}`;
|
|
19
|
+
readonly feeLcai: number;
|
|
20
|
+
constructor(args: {
|
|
21
|
+
jobId: bigint;
|
|
22
|
+
worker: `0x${string}`;
|
|
23
|
+
submitTx: `0x${string}`;
|
|
24
|
+
feeLcai: number;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The on-chain `createSession` or `submitJob` reverted with a contract-level
|
|
29
|
+
* error (NOT a "wallet too poor for gas" error, which surfaces as a viem error
|
|
30
|
+
* before the tx broadcasts). Surfaces the function name and tx hash so the
|
|
31
|
+
* caller can inspect on the explorer.
|
|
32
|
+
*/
|
|
33
|
+
export declare class OnChainRevertError extends Error {
|
|
34
|
+
readonly fn: "createSession" | "submitJob";
|
|
35
|
+
readonly tx: `0x${string}`;
|
|
36
|
+
constructor(fn: "createSession" | "submitJob", tx: `0x${string}`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The relay token endpoint never returned a usable token inside the poll window.
|
|
40
|
+
* Usually means the gateway dispatcher couldn't finalise the session - rare in
|
|
41
|
+
* practice. Re-running creates a fresh session.
|
|
42
|
+
*/
|
|
43
|
+
export declare class RelayTokenTimeoutError extends Error {
|
|
44
|
+
constructor();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Authentication or authorisation issue with the consumer gateway - the caller
|
|
48
|
+
* passed a bad/expired JWT, or the upstream rejected the SIWE handshake.
|
|
49
|
+
*/
|
|
50
|
+
export declare class GatewayAuthError extends Error {
|
|
51
|
+
readonly status: number;
|
|
52
|
+
constructor(status: number, body: string);
|
|
53
|
+
}
|
|
54
|
+
/** Convenience predicate so callers don't need `instanceof` if they don't want it. */
|
|
55
|
+
export declare function isStalledWorker(e: unknown): e is StalledWorkerError;
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors thrown by the high-level helpers (`runInference`, gateway calls
|
|
3
|
+
* inside `prepareSession`, etc.). Catching by class lets callers branch on the
|
|
4
|
+
* failure mode cleanly instead of regexing message strings.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* The dispatcher picked a worker and the on-chain `submitJob` succeeded, but the
|
|
8
|
+
* worker never emitted `JobCompleted` inside the deadline. The protocol times
|
|
9
|
+
* out and refunds the escrowed fee after its dispute window (a few hours on
|
|
10
|
+
* testnet, ~24h on mainnet); the consumer does not need to call any timeoutJob.
|
|
11
|
+
*
|
|
12
|
+
* Re-running creates a NEW session with a different worker - the assignment is
|
|
13
|
+
* stochastic, so a retry almost always lands on a healthy one.
|
|
14
|
+
*/
|
|
15
|
+
export class StalledWorkerError extends Error {
|
|
16
|
+
constructor(args) {
|
|
17
|
+
super(`worker stalled (jobId=${args.jobId} worker=${args.worker}): no JobCompleted inside the deadline. The protocol will refund the ${args.feeLcai} LCAI fee after the dispute window.`);
|
|
18
|
+
this.name = "StalledWorkerError";
|
|
19
|
+
this.jobId = args.jobId;
|
|
20
|
+
this.worker = args.worker;
|
|
21
|
+
this.submitTx = args.submitTx;
|
|
22
|
+
this.feeLcai = args.feeLcai;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The on-chain `createSession` or `submitJob` reverted with a contract-level
|
|
27
|
+
* error (NOT a "wallet too poor for gas" error, which surfaces as a viem error
|
|
28
|
+
* before the tx broadcasts). Surfaces the function name and tx hash so the
|
|
29
|
+
* caller can inspect on the explorer.
|
|
30
|
+
*/
|
|
31
|
+
export class OnChainRevertError extends Error {
|
|
32
|
+
constructor(fn, tx) {
|
|
33
|
+
super(`${fn} reverted on-chain (tx=${tx})`);
|
|
34
|
+
this.name = "OnChainRevertError";
|
|
35
|
+
this.fn = fn;
|
|
36
|
+
this.tx = tx;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The relay token endpoint never returned a usable token inside the poll window.
|
|
41
|
+
* Usually means the gateway dispatcher couldn't finalise the session - rare in
|
|
42
|
+
* practice. Re-running creates a fresh session.
|
|
43
|
+
*/
|
|
44
|
+
export class RelayTokenTimeoutError extends Error {
|
|
45
|
+
constructor() {
|
|
46
|
+
super("the gateway never issued a relay token for this session (poll timed out)");
|
|
47
|
+
this.name = "RelayTokenTimeoutError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Authentication or authorisation issue with the consumer gateway - the caller
|
|
52
|
+
* passed a bad/expired JWT, or the upstream rejected the SIWE handshake.
|
|
53
|
+
*/
|
|
54
|
+
export class GatewayAuthError extends Error {
|
|
55
|
+
constructor(status, body) {
|
|
56
|
+
super(`gateway auth failed (${status}): ${body.slice(0, 200)}`);
|
|
57
|
+
this.name = "GatewayAuthError";
|
|
58
|
+
this.status = status;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Convenience predicate so callers don't need `instanceof` if they don't want it. */
|
|
62
|
+
export function isStalledWorker(e) {
|
|
63
|
+
return e instanceof StalledWorkerError;
|
|
64
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS } from "./networks.js";
|
|
2
2
|
import { fromWei } from "./subgraph.js";
|
|
3
3
|
import { aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv } from "./analytics.js";
|
|
4
|
-
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair } from "./inference.js";
|
|
4
|
+
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference } from "./inference.js";
|
|
5
|
+
import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker } from "./errors.js";
|
|
5
6
|
import { GatewayClient, GatewayHttpError } from "./gateway.js";
|
|
6
7
|
import * as crypto from "./crypto.js";
|
|
7
8
|
import type { NetworkId, NetworkConfig, Worker, Job, ModelInfo, NetworkStats, ModelStat, WorkerStat, NetworkAnalytics } from "./types.js";
|
|
@@ -59,7 +60,7 @@ export declare class LightNode {
|
|
|
59
60
|
baseUrl?: string;
|
|
60
61
|
}): GatewayClient;
|
|
61
62
|
}
|
|
62
|
-
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, };
|
|
63
|
+
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, };
|
|
63
64
|
export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
|
|
64
|
-
export type { SessionPreparation } from "./inference.js";
|
|
65
|
+
export type { SessionPreparation, RunInferenceArgs, RunInferenceResult } from "./inference.js";
|
|
65
66
|
export type { NetworkId, NetworkConfig, Worker, Job, ModelInfo, NetworkStats, ModelStat, WorkerStat, NetworkAnalytics };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,8 @@ import { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS } from "./networks.js";
|
|
|
2
2
|
import { fetchWorker, fetchWorkerJobs, fetchRecentJobs, fetchModels, fetchWorkers, summarize, fromWei, } from "./subgraph.js";
|
|
3
3
|
import { isRegistered } from "./onchain.js";
|
|
4
4
|
import { aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, } from "./analytics.js";
|
|
5
|
-
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, } from "./inference.js";
|
|
5
|
+
import { modelId as computeModelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, runInference, } from "./inference.js";
|
|
6
|
+
import { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, } from "./errors.js";
|
|
6
7
|
import { GatewayClient, GatewayHttpError } from "./gateway.js";
|
|
7
8
|
import * as crypto from "./crypto.js";
|
|
8
9
|
/**
|
|
@@ -91,4 +92,6 @@ export class LightNode {
|
|
|
91
92
|
}
|
|
92
93
|
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl,
|
|
93
94
|
// v0.3 inference-submit surface (BETA - see README "Submitting inference").
|
|
94
|
-
GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto,
|
|
95
|
+
GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto,
|
|
96
|
+
// v0.4 high-level orchestrator: one call, full flow.
|
|
97
|
+
runInference, StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker, };
|
package/dist/inference.d.ts
CHANGED
|
@@ -94,3 +94,133 @@ export declare function decryptResponse(sessionKey: Uint8Array, ciphertext: Uint
|
|
|
94
94
|
export { consumerGatewayUrl, GatewayClient } from "./gateway.js";
|
|
95
95
|
/** Optional helper: generate the caller's own ECDH keypair if they want one (e.g. acting as the disputer). */
|
|
96
96
|
export { generateEcdhKeyPair };
|
|
97
|
+
interface MinimalWalletClient {
|
|
98
|
+
writeContract: (args: {
|
|
99
|
+
address: `0x${string}`;
|
|
100
|
+
abi: readonly unknown[];
|
|
101
|
+
functionName: string;
|
|
102
|
+
args: readonly unknown[];
|
|
103
|
+
value?: bigint;
|
|
104
|
+
gas?: bigint;
|
|
105
|
+
}) => Promise<`0x${string}`>;
|
|
106
|
+
}
|
|
107
|
+
interface MinimalPublicClient {
|
|
108
|
+
waitForTransactionReceipt: (args: {
|
|
109
|
+
hash: `0x${string}`;
|
|
110
|
+
}) => Promise<{
|
|
111
|
+
status: "success" | "reverted";
|
|
112
|
+
blockHash: `0x${string}`;
|
|
113
|
+
blockNumber: bigint;
|
|
114
|
+
}>;
|
|
115
|
+
getLogs: (args: {
|
|
116
|
+
address: `0x${string}`;
|
|
117
|
+
event?: unknown;
|
|
118
|
+
args?: Record<string, unknown>;
|
|
119
|
+
fromBlock?: bigint;
|
|
120
|
+
toBlock?: bigint | "latest";
|
|
121
|
+
blockHash?: `0x${string}`;
|
|
122
|
+
}) => Promise<Array<{
|
|
123
|
+
transactionHash: `0x${string}`;
|
|
124
|
+
blockNumber: bigint;
|
|
125
|
+
data: `0x${string}`;
|
|
126
|
+
topics: `0x${string}`[];
|
|
127
|
+
args?: Record<string, unknown>;
|
|
128
|
+
}>>;
|
|
129
|
+
}
|
|
130
|
+
interface MinimalWebSocket {
|
|
131
|
+
binaryType?: string;
|
|
132
|
+
close: () => void;
|
|
133
|
+
addEventListener?: (type: "message" | "open" | "error" | "close", listener: (ev: {
|
|
134
|
+
data?: unknown;
|
|
135
|
+
}) => void, options?: {
|
|
136
|
+
once?: boolean;
|
|
137
|
+
}) => void;
|
|
138
|
+
on?: (type: "message" | "open" | "error" | "close", listener: (data?: unknown) => void) => void;
|
|
139
|
+
once?: (type: "open" | "error" | "close", listener: (data?: unknown) => void) => void;
|
|
140
|
+
}
|
|
141
|
+
type WebSocketCtor = new (url: string) => MinimalWebSocket;
|
|
142
|
+
export interface RunInferenceArgs {
|
|
143
|
+
/** The plaintext prompt to send. UTF-8 encoded before encryption. */
|
|
144
|
+
prompt: string;
|
|
145
|
+
/** Authenticated GatewayClient (with bearer JWT). */
|
|
146
|
+
gateway: GatewayClient;
|
|
147
|
+
/** viem WalletClient used to sign createSession + submitJob. */
|
|
148
|
+
wallet: MinimalWalletClient;
|
|
149
|
+
/** viem PublicClient used for receipts + log queries. */
|
|
150
|
+
publicClient: MinimalPublicClient;
|
|
151
|
+
/** The target NetworkConfig (typically `new LightNode("testnet").network`). */
|
|
152
|
+
network: NetworkConfig;
|
|
153
|
+
/** Inference model tag. Default: `"llama3-8b"`. */
|
|
154
|
+
model?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Streaming callback invoked once per decrypted relay chunk. Use for live
|
|
157
|
+
* stdout / UI updates. Optional - the final `answer` is returned either way.
|
|
158
|
+
*/
|
|
159
|
+
onChunk?: (chunk: string, totalSoFar: string) => void;
|
|
160
|
+
/** Retry count if a worker stalls. Default 2 (so up to 3 paid attempts). */
|
|
161
|
+
maxRetries?: number;
|
|
162
|
+
/** How long to wait for JobCompleted before declaring the worker stalled. Default 90s. */
|
|
163
|
+
jobCompletedTimeoutMs?: number;
|
|
164
|
+
/**
|
|
165
|
+
* WebSocket constructor. In a browser, omit and `globalThis.WebSocket` is
|
|
166
|
+
* used. In Node, pass `WS` from the `ws` package.
|
|
167
|
+
*/
|
|
168
|
+
WebSocket?: WebSocketCtor;
|
|
169
|
+
/**
|
|
170
|
+
* Override the relay URL (defaults to `wss://relay.<network>.lightchain.ai/ws`).
|
|
171
|
+
* Useful for tests / mirrors.
|
|
172
|
+
*/
|
|
173
|
+
relayUrl?: string;
|
|
174
|
+
}
|
|
175
|
+
export interface RunInferenceResult {
|
|
176
|
+
/** The decrypted, fully-assembled model answer. */
|
|
177
|
+
answer: string;
|
|
178
|
+
/** The three on-chain transactions in the chain of proof. */
|
|
179
|
+
txs: {
|
|
180
|
+
createSession: `0x${string}`;
|
|
181
|
+
submitJob: `0x${string}`;
|
|
182
|
+
jobCompleted: `0x${string}`;
|
|
183
|
+
};
|
|
184
|
+
/** The dispatcher-assigned worker that produced this response. */
|
|
185
|
+
worker: `0x${string}`;
|
|
186
|
+
sessionId: bigint;
|
|
187
|
+
jobId: bigint;
|
|
188
|
+
/** How many attempts were paid for (including the successful one). */
|
|
189
|
+
attempts: number;
|
|
190
|
+
/** Any prior attempts whose workers stalled (their fees are refunded by the protocol). */
|
|
191
|
+
stalled: Array<{
|
|
192
|
+
jobId: bigint;
|
|
193
|
+
worker: `0x${string}`;
|
|
194
|
+
submitTx: `0x${string}`;
|
|
195
|
+
}>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* One call, full encrypted inference. Same code path the live playground at
|
|
199
|
+
* lightnode.app/playground drives, condensed into a single function.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* import { LightNode, runInference, GatewayClient } from "lightnode-sdk";
|
|
204
|
+
* import { createPublicClient, createWalletClient, http } from "viem";
|
|
205
|
+
* import { privateKeyToAccount } from "viem/accounts";
|
|
206
|
+
* import WS from "ws";
|
|
207
|
+
*
|
|
208
|
+
* const ln = new LightNode("testnet");
|
|
209
|
+
* const wallet = createWalletClient({ account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`), transport: http(ln.network.rpc) });
|
|
210
|
+
* const publicClient = createPublicClient({ transport: http(ln.network.rpc) });
|
|
211
|
+
* const gateway = new GatewayClient({ network: "testnet", bearer: await getJwt() });
|
|
212
|
+
*
|
|
213
|
+
* const { answer, txs } = await runInference({
|
|
214
|
+
* prompt: "Reply with a one-sentence fun fact about the ocean.",
|
|
215
|
+
* gateway, wallet, publicClient, network: ln.network,
|
|
216
|
+
* WebSocket: WS, // omit in the browser
|
|
217
|
+
* onChunk: (chunk) => process.stdout.write(chunk),
|
|
218
|
+
* maxRetries: 2,
|
|
219
|
+
* });
|
|
220
|
+
*
|
|
221
|
+
* console.log("\n", txs);
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
export declare function runInference(args: RunInferenceArgs): Promise<RunInferenceResult>;
|
|
225
|
+
/** Re-export the typed errors at this layer so a single import covers everything. */
|
|
226
|
+
export { StalledWorkerError, OnChainRevertError, RelayTokenTimeoutError, GatewayAuthError, isStalledWorker } from "./errors.js";
|