lightnode-sdk 0.9.0 → 0.9.2

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/add.js CHANGED
@@ -1085,17 +1085,17 @@ export default function ChatWeb3() {
1085
1085
  setBusyStage("");
1086
1086
  patchLastAssistant({ text: totalSoFar });
1087
1087
  };
1088
+ const onStage = (s: string) => setBusyStage(s);
1089
+ const sendOpts = { onChunk, onStage };
1088
1090
 
1089
1091
  const chat = await ensureSession();
1090
- setBusyStage("Approve the per-turn transaction in your wallet...");
1091
- const result = await chat.send(prompt, { onChunk }).catch(async () => {
1092
+ const result = await chat.send(prompt, sendOpts).catch(async () => {
1092
1093
  // Session expired or the worker stopped serving - reopen once and retry.
1093
1094
  sessionRef.current = null;
1094
1095
  patchLastAssistant({ text: "" });
1095
1096
  setBusyStage("Re-opening session...");
1096
1097
  const fresh = await ensureSession();
1097
- setBusyStage("Approve the per-turn transaction in your wallet...");
1098
- return fresh.send(prompt, { onChunk });
1098
+ return fresh.send(prompt, sendOpts);
1099
1099
  });
1100
1100
 
1101
1101
  patchLastAssistant({
@@ -1181,7 +1181,7 @@ export default function ChatWeb3() {
1181
1181
  )
1182
1182
  ) : (
1183
1183
  <div className="animate-pulse-dot pt-1 text-sm text-muted-foreground">
1184
- {busyStage || "Writing on chain..."}
1184
+ {busyStage || "Thinking..."}
1185
1185
  </div>
1186
1186
  )}
1187
1187
  {t.submitTx && (
@@ -235,6 +235,8 @@ export interface OpenSessionArgs {
235
235
  export declare function openSession(args: OpenSessionArgs): Promise<OpenSession>;
236
236
  export interface RunJobOpts {
237
237
  onChunk?: (chunk: string, totalSoFar: string) => void;
238
+ /** Human-readable progress, e.g. "Uploading prompt to chain..." then "Thinking...". */
239
+ onStage?: (stage: string) => void;
238
240
  jobCompletedTimeoutMs?: number;
239
241
  WebSocket?: WebSocketCtor;
240
242
  relayUrl?: string;
package/dist/inference.js CHANGED
@@ -277,19 +277,28 @@ export async function openSession(args) {
277
277
  */
278
278
  export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
279
279
  const { gateway, wallet, publicClient, network, sessionId, sessionKey, worker, fee, createTx } = session;
280
- const { onChunk, jobCompletedTimeoutMs = 120000 } = opts;
280
+ const { onChunk, onStage, jobCompletedTimeoutMs = 120000 } = opts;
281
281
  const WS = pickWebSocket(opts.WebSocket);
282
282
  const relayUrl = opts.relayUrl ?? `wss://relay.${network.id}.lightchain.ai/ws`;
283
283
  // Shim so the job body below can keep referencing prepared.* unchanged.
284
284
  const prepared = { sessionKey, createSessionArgs: { worker } };
285
285
  // 3. relay token + WebSocket
286
+ // Poll the gateway for the relay token with a fast backoff (it's usually ready
287
+ // within ~1s of createSession). Catch it sooner than a fixed 1s interval, and
288
+ // cap the total at a 20s deadline instead of 30 fixed iterations.
286
289
  let relayToken;
287
- for (let i = 0; i < 30 && !relayToken; i++) {
290
+ const tokenDeadline = Date.now() + 20000;
291
+ let tokenDelay = 250;
292
+ while (!relayToken) {
288
293
  const r = await gateway.getSessionToken(Number(sessionId));
289
- if ("token" in r && r.token)
294
+ if ("token" in r && r.token) {
290
295
  relayToken = r.token;
291
- else
292
- await new Promise((res) => setTimeout(res, 1000));
296
+ break;
297
+ }
298
+ if (Date.now() >= tokenDeadline)
299
+ break;
300
+ await new Promise((res) => setTimeout(res, tokenDelay));
301
+ tokenDelay = Math.min(tokenDelay * 2, 2000);
293
302
  }
294
303
  if (!relayToken)
295
304
  throw new RelayTokenTimeoutError();
@@ -373,6 +382,7 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
373
382
  ws.addEventListener("message", (ev) => handleMessage(ev.data));
374
383
  }
375
384
  // 4. encrypt + upload prompt
385
+ onStage?.("Uploading prompt to chain...");
376
386
  const promptHash = await submitPrompt(gateway, prepared.sessionKey, prompt);
377
387
  // 5. submitJob on-chain
378
388
  const submitTx = await wallet.writeContract({
@@ -397,6 +407,7 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
397
407
  if (!jobLog)
398
408
  throw new Error("JobSubmitted log missing in submitJob receipt");
399
409
  const jobId = topicAsUint(jobLog.topics[1]);
410
+ onStage?.("Thinking...");
400
411
  // 6. wait for JobCompleted
401
412
  // The actual *result* is the WS-delivered, session-key-decrypted ciphertext.
402
413
  // JobCompleted is an explorer pointer (the worker's commit-result tx).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightnode-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
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",