lightnode-sdk 0.9.2 → 0.10.1
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/gateway.d.ts +18 -4
- package/dist/gateway.js +22 -6
- package/dist/index.d.ts +1 -1
- package/dist/inference.d.ts +30 -2
- package/dist/inference.js +62 -8
- package/package.json +1 -1
package/dist/gateway.d.ts
CHANGED
|
@@ -92,8 +92,19 @@ export declare class GatewayClient {
|
|
|
92
92
|
name: string;
|
|
93
93
|
}[];
|
|
94
94
|
}>;
|
|
95
|
-
/** Protected: dispatcher picks a worker for a session and returns its pubkey.
|
|
96
|
-
|
|
95
|
+
/** Protected: dispatcher picks a worker for a session and returns its pubkey.
|
|
96
|
+
* Pass requiredCapabilities (e.g. ["search"]) to bind only to a worker that
|
|
97
|
+
* advertises them. */
|
|
98
|
+
selectSession(modelId: `0x${string}`, opts?: {
|
|
99
|
+
requiredCapabilities?: string[];
|
|
100
|
+
}): Promise<SelectSessionResult>;
|
|
101
|
+
/** Public: union of capabilities advertised by active workers for a model
|
|
102
|
+
* (e.g. ["search"]). Used to gate UI before a session binds. Note: this
|
|
103
|
+
* endpoint may 404 on networks where consumer-api hasn't deployed it yet. */
|
|
104
|
+
getModelCapabilities(modelIdHex: `0x${string}`): Promise<{
|
|
105
|
+
modelId: string;
|
|
106
|
+
capabilities: string[];
|
|
107
|
+
}>;
|
|
97
108
|
/**
|
|
98
109
|
* Protected: hand the dispatcher the encrypted session key it can give the
|
|
99
110
|
* worker, get back the EIP-712 signature authorising on-chain createSession.
|
|
@@ -116,8 +127,11 @@ export declare class GatewayClient {
|
|
|
116
127
|
selectionId?: string;
|
|
117
128
|
requiredCapabilities?: string[];
|
|
118
129
|
}): Promise<PrepareSessionResult>;
|
|
119
|
-
/** Protected: upload an encrypted prompt blob; returns the EIP-4844 blob hash.
|
|
120
|
-
|
|
130
|
+
/** Protected: upload an encrypted prompt blob; returns the EIP-4844 blob hash.
|
|
131
|
+
* Pass { searchEnabled: true } to opt this job into worker-side web search. */
|
|
132
|
+
uploadBlob(base64Data: string, opts?: {
|
|
133
|
+
searchEnabled?: boolean;
|
|
134
|
+
}): Promise<UploadBlobResult>;
|
|
121
135
|
/** Protected: fetch the relay JWT for an active session (202 = pending). */
|
|
122
136
|
getSessionToken(sessionId: number): Promise<SessionTokenResult>;
|
|
123
137
|
private req;
|
package/dist/gateway.js
CHANGED
|
@@ -75,9 +75,21 @@ export class GatewayClient {
|
|
|
75
75
|
getModels() {
|
|
76
76
|
return this.req("GET", "/api/models");
|
|
77
77
|
}
|
|
78
|
-
/** Protected: dispatcher picks a worker for a session and returns its pubkey.
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
/** Protected: dispatcher picks a worker for a session and returns its pubkey.
|
|
79
|
+
* Pass requiredCapabilities (e.g. ["search"]) to bind only to a worker that
|
|
80
|
+
* advertises them. */
|
|
81
|
+
selectSession(modelId, opts) {
|
|
82
|
+
const body = { modelId };
|
|
83
|
+
if (opts?.requiredCapabilities && opts.requiredCapabilities.length > 0) {
|
|
84
|
+
body.requiredCapabilities = opts.requiredCapabilities;
|
|
85
|
+
}
|
|
86
|
+
return this.req("POST", "/api/sessions/select", body);
|
|
87
|
+
}
|
|
88
|
+
/** Public: union of capabilities advertised by active workers for a model
|
|
89
|
+
* (e.g. ["search"]). Used to gate UI before a session binds. Note: this
|
|
90
|
+
* endpoint may 404 on networks where consumer-api hasn't deployed it yet. */
|
|
91
|
+
getModelCapabilities(modelIdHex) {
|
|
92
|
+
return this.req("GET", `/api/models/${modelIdHex}/capabilities`);
|
|
81
93
|
}
|
|
82
94
|
/**
|
|
83
95
|
* Protected: hand the dispatcher the encrypted session key it can give the
|
|
@@ -92,9 +104,13 @@ export class GatewayClient {
|
|
|
92
104
|
prepareSession(input) {
|
|
93
105
|
return this.req("POST", "/api/sessions/prepare", input);
|
|
94
106
|
}
|
|
95
|
-
/** Protected: upload an encrypted prompt blob; returns the EIP-4844 blob hash.
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
/** Protected: upload an encrypted prompt blob; returns the EIP-4844 blob hash.
|
|
108
|
+
* Pass { searchEnabled: true } to opt this job into worker-side web search. */
|
|
109
|
+
uploadBlob(base64Data, opts) {
|
|
110
|
+
const body = { data: base64Data };
|
|
111
|
+
if (opts?.searchEnabled === true)
|
|
112
|
+
body.searchEnabled = true;
|
|
113
|
+
return this.req("POST", "/api/blobs", body);
|
|
98
114
|
}
|
|
99
115
|
/** Protected: fetch the relay JWT for an active session (202 = pending). */
|
|
100
116
|
getSessionToken(sessionId) {
|
package/dist/index.d.ts
CHANGED
|
@@ -137,7 +137,7 @@ export declare class LightNode {
|
|
|
137
137
|
export declare const SDK_VERSION = "0.7.20";
|
|
138
138
|
export { NETWORKS, WORKER_REGISTRY, REGISTRY_TOPICS, aggregateModelStats, aggregateWorkerStats, networkAnalytics, modelStatsCsv, workerStatsCsv, workerJobsCsv, fromWei, resolveJobTransactions, siweSignIn, siweChallenge, siweVerify, fetchWorkerModels, computeModelId as modelId, estimateJobFee, JOB_REGISTRY_CONSUMER_ABI, consumerGatewayUrl, consumerGatewayHost, GatewayClient, GatewayHttpError, prepareSession, submitPrompt, decryptResponse, generateEcdhKeyPair, crypto, runInference, runInferenceWithKey, runInferenceStream, openSession, runJobOnSession, LightChatSession, 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, };
|
|
139
139
|
export type { BearerSource, GatewayClientOptions, SelectSessionResult, PrepareSessionResult, UploadBlobResult, SessionTokenResult } from "./gateway.js";
|
|
140
|
-
export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult } from "./inference.js";
|
|
140
|
+
export type { SessionPreparation, RunInferenceArgs, RunInferenceResult, RunInferenceWithKeyArgs, RunInferenceStreamResult, OpenSession, OpenSessionArgs, RunJobOpts, WebSearchSource } from "./inference.js";
|
|
141
141
|
export type { ChatRole, ChatMessage, ConversationOptions, ConversationSendResult } from "./chat.js";
|
|
142
142
|
export type { BatchPrompt, BatchResult, RunInferenceBatchArgs } from "./batch.js";
|
|
143
143
|
export type { AgentTool, AgentStep, AgentOptions, AgentRunResult } from "./agent.js";
|
package/dist/inference.d.ts
CHANGED
|
@@ -73,6 +73,8 @@ export interface SessionPreparation {
|
|
|
73
73
|
expiry: bigint;
|
|
74
74
|
};
|
|
75
75
|
nonce: number;
|
|
76
|
+
/** Capabilities the bound worker advertises (e.g. ["search"]). */
|
|
77
|
+
workerCapabilities?: string[];
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
78
80
|
* Step 1 + 2 of the protocol: ask the gateway which worker to use, generate a
|
|
@@ -82,12 +84,16 @@ export interface SessionPreparation {
|
|
|
82
84
|
* After this returns, the caller submits the on-chain `createSession` tx with
|
|
83
85
|
* `createSessionArgs` and remembers `sessionKey` for the rest of the session.
|
|
84
86
|
*/
|
|
85
|
-
export declare function prepareSession(gateway: GatewayClient, modelTag: string
|
|
87
|
+
export declare function prepareSession(gateway: GatewayClient, modelTag: string, opts?: {
|
|
88
|
+
requiredCapabilities?: string[];
|
|
89
|
+
}): Promise<SessionPreparation>;
|
|
86
90
|
/**
|
|
87
91
|
* Encrypt a UTF-8 prompt with the session key, upload as a blob, and return
|
|
88
92
|
* the EIP-4844 blob hash to pass to `submitJob(sessionId, blobHash)`.
|
|
89
93
|
*/
|
|
90
|
-
export declare function submitPrompt(gateway: GatewayClient, sessionKey: Uint8Array, prompt: string
|
|
94
|
+
export declare function submitPrompt(gateway: GatewayClient, sessionKey: Uint8Array, prompt: string, opts?: {
|
|
95
|
+
searchEnabled?: boolean;
|
|
96
|
+
}): Promise<`0x${string}`>;
|
|
91
97
|
/** Decrypt a worker response (raw bytes or base64 from the relay) with the session key. */
|
|
92
98
|
export declare function decryptResponse(sessionKey: Uint8Array, ciphertext: Uint8Array | string): Promise<string>;
|
|
93
99
|
/** Re-export so callers don't have to import from a second module just for the URL helper. */
|
|
@@ -152,6 +158,8 @@ export interface RunInferenceArgs {
|
|
|
152
158
|
network: NetworkConfig;
|
|
153
159
|
/** Inference model tag. Default: `"llama3-8b"`. */
|
|
154
160
|
model?: string;
|
|
161
|
+
/** Opt into worker-side web search (needs a search-capable worker). */
|
|
162
|
+
searchEnabled?: boolean;
|
|
155
163
|
/**
|
|
156
164
|
* Streaming callback invoked once per decrypted relay chunk. Use for live
|
|
157
165
|
* stdout / UI updates. Optional - the final `answer` is returned either way.
|
|
@@ -203,6 +211,8 @@ export interface RunInferenceResult {
|
|
|
203
211
|
worker: `0x${string}`;
|
|
204
212
|
submitTx: `0x${string}`;
|
|
205
213
|
}>;
|
|
214
|
+
/** Web-search citations, when searchEnabled and the worker returned them. */
|
|
215
|
+
sources?: WebSearchSource[];
|
|
206
216
|
}
|
|
207
217
|
/** A live, on-chain session. Open once, then run many jobs through it - each
|
|
208
218
|
* follow-up turn skips SIWE + createSession, leaving just the submitJob tx. */
|
|
@@ -219,6 +229,8 @@ export interface OpenSession {
|
|
|
219
229
|
readonly createTx: `0x${string}`;
|
|
220
230
|
/** Unix seconds when the on-chain session window closes. */
|
|
221
231
|
readonly expirySec: number;
|
|
232
|
+
/** Capabilities the bound worker advertises (e.g. ["search"]). */
|
|
233
|
+
readonly capabilities: string[];
|
|
222
234
|
}
|
|
223
235
|
export interface OpenSessionArgs {
|
|
224
236
|
gateway: GatewayClient;
|
|
@@ -226,6 +238,8 @@ export interface OpenSessionArgs {
|
|
|
226
238
|
publicClient: MinimalPublicClient;
|
|
227
239
|
network: NetworkConfig;
|
|
228
240
|
model?: string;
|
|
241
|
+
/** Bind only to a worker advertising these (e.g. ["search"]). */
|
|
242
|
+
requiredCapabilities?: string[];
|
|
229
243
|
}
|
|
230
244
|
/**
|
|
231
245
|
* prepareSession + the on-chain createSession tx. Do this once, then run many
|
|
@@ -233,8 +247,18 @@ export interface OpenSessionArgs {
|
|
|
233
247
|
* passes or the chosen worker stops serving.
|
|
234
248
|
*/
|
|
235
249
|
export declare function openSession(args: OpenSessionArgs): Promise<OpenSession>;
|
|
250
|
+
/** A web-search citation returned alongside an answer (from the worker's
|
|
251
|
+
* "metadata" relay frame when searchEnabled was set). */
|
|
252
|
+
export interface WebSearchSource {
|
|
253
|
+
position: number;
|
|
254
|
+
title: string;
|
|
255
|
+
url: string;
|
|
256
|
+
description: string;
|
|
257
|
+
}
|
|
236
258
|
export interface RunJobOpts {
|
|
237
259
|
onChunk?: (chunk: string, totalSoFar: string) => void;
|
|
260
|
+
/** Opt this job into worker-side web search (requires a search-capable worker). */
|
|
261
|
+
searchEnabled?: boolean;
|
|
238
262
|
/** Human-readable progress, e.g. "Uploading prompt to chain..." then "Thinking...". */
|
|
239
263
|
onStage?: (stage: string) => void;
|
|
240
264
|
jobCompletedTimeoutMs?: number;
|
|
@@ -268,6 +292,8 @@ export declare class LightChatSession {
|
|
|
268
292
|
get sessionId(): bigint;
|
|
269
293
|
get worker(): `0x${string}`;
|
|
270
294
|
get model(): string;
|
|
295
|
+
/** Capabilities the bound worker advertises (e.g. ["search"]). */
|
|
296
|
+
get capabilities(): string[];
|
|
271
297
|
/** true once the on-chain session window has closed; re-open before sending. */
|
|
272
298
|
get expired(): boolean;
|
|
273
299
|
send(prompt: string, opts?: RunJobOpts): Promise<RunInferenceResult>;
|
|
@@ -315,6 +341,8 @@ export interface RunInferenceWithKeyArgs {
|
|
|
315
341
|
prompt: string;
|
|
316
342
|
/** Inference model tag. Default: `"llama3-8b"`. */
|
|
317
343
|
model?: string;
|
|
344
|
+
/** Opt into worker-side web search (needs a search-capable worker). */
|
|
345
|
+
searchEnabled?: boolean;
|
|
318
346
|
/**
|
|
319
347
|
* Streaming callback invoked once per decrypted relay chunk. Use for live
|
|
320
348
|
* stdout / UI updates. Optional - the final `answer` is returned either way.
|
package/dist/inference.js
CHANGED
|
@@ -73,8 +73,9 @@ export const JOB_REGISTRY_CONSUMER_ABI = [
|
|
|
73
73
|
* After this returns, the caller submits the on-chain `createSession` tx with
|
|
74
74
|
* `createSessionArgs` and remembers `sessionKey` for the rest of the session.
|
|
75
75
|
*/
|
|
76
|
-
export async function prepareSession(gateway, modelTag) {
|
|
76
|
+
export async function prepareSession(gateway, modelTag, opts) {
|
|
77
77
|
const id = modelId(modelTag);
|
|
78
|
+
const requiredCapabilities = opts?.requiredCapabilities;
|
|
78
79
|
// The gateway returns 409 selection_mismatch when a NEWER selectSession()
|
|
79
80
|
// for the same wallet supersedes ours between the select and the prepare.
|
|
80
81
|
// The error message is literally "re-run POST /api/sessions/select", so we
|
|
@@ -98,7 +99,7 @@ export async function prepareSession(gateway, modelTag) {
|
|
|
98
99
|
// call has already superseded ours by the time the gateway processes
|
|
99
100
|
// it. prepareSession 409s when the same happens between select and
|
|
100
101
|
// prepare. The whole select -> prepare flow is one atomic unit.
|
|
101
|
-
const selected = await gateway.selectSession(id);
|
|
102
|
+
const selected = await gateway.selectSession(id, requiredCapabilities ? { requiredCapabilities } : undefined);
|
|
102
103
|
const sessionKey = await generateSessionKey();
|
|
103
104
|
// Workers' pubkeys arrive as base64; disputer's as hex - decodePublicKey
|
|
104
105
|
// accepts either.
|
|
@@ -119,10 +120,12 @@ export async function prepareSession(gateway, modelTag) {
|
|
|
119
120
|
encWorkerKey: bytesToBase64(encWorker),
|
|
120
121
|
encDisputerKey: bytesToBase64(encDisputer),
|
|
121
122
|
...(selected.selectionId ? { selectionId: selected.selectionId } : {}),
|
|
123
|
+
...(requiredCapabilities ? { requiredCapabilities } : {}),
|
|
122
124
|
});
|
|
123
125
|
return {
|
|
124
126
|
sessionKey,
|
|
125
127
|
nonce: prepared.nonce,
|
|
128
|
+
workerCapabilities: selected.workerCapabilities ?? [],
|
|
126
129
|
createSessionArgs: {
|
|
127
130
|
paramsHash: id,
|
|
128
131
|
worker: prepared.worker,
|
|
@@ -148,9 +151,9 @@ export async function prepareSession(gateway, modelTag) {
|
|
|
148
151
|
* Encrypt a UTF-8 prompt with the session key, upload as a blob, and return
|
|
149
152
|
* the EIP-4844 blob hash to pass to `submitJob(sessionId, blobHash)`.
|
|
150
153
|
*/
|
|
151
|
-
export async function submitPrompt(gateway, sessionKey, prompt) {
|
|
154
|
+
export async function submitPrompt(gateway, sessionKey, prompt, opts) {
|
|
152
155
|
const ct = await encrypt(sessionKey, utf8ToBytes(prompt));
|
|
153
|
-
const res = await gateway.uploadBlob(bytesToBase64(ct));
|
|
156
|
+
const res = await gateway.uploadBlob(bytesToBase64(ct), opts?.searchEnabled ? { searchEnabled: true } : undefined);
|
|
154
157
|
const first = res.blobHashes?.[0];
|
|
155
158
|
if (!first)
|
|
156
159
|
throw new Error("gateway returned no blob hashes");
|
|
@@ -228,6 +231,37 @@ function pickWebSocket(provided) {
|
|
|
228
231
|
function topicAsUint(hex) {
|
|
229
232
|
return BigInt(hex);
|
|
230
233
|
}
|
|
234
|
+
/** Parse a decrypted "metadata" relay frame into web-search citations. Mirrors
|
|
235
|
+
* lcai-chat-v2's parseWebSearchSources: requires type === "webSearchSources"
|
|
236
|
+
* and an array of { position:number, url:string, title?, snippet? }. */
|
|
237
|
+
function parseWebSearchSources(payload) {
|
|
238
|
+
let parsed;
|
|
239
|
+
try {
|
|
240
|
+
parsed = JSON.parse(payload);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
if (!parsed || typeof parsed !== "object")
|
|
246
|
+
return [];
|
|
247
|
+
const obj = parsed;
|
|
248
|
+
if (obj.type !== "webSearchSources" || !Array.isArray(obj.sources))
|
|
249
|
+
return [];
|
|
250
|
+
const out = [];
|
|
251
|
+
for (const s of obj.sources) {
|
|
252
|
+
if (!s || typeof s !== "object")
|
|
253
|
+
continue;
|
|
254
|
+
const src = s;
|
|
255
|
+
const position = typeof src.position === "number" ? src.position : undefined;
|
|
256
|
+
const url = typeof src.url === "string" ? src.url : "";
|
|
257
|
+
const title = typeof src.title === "string" ? src.title : "";
|
|
258
|
+
const snippet = typeof src.snippet === "string" ? src.snippet : "";
|
|
259
|
+
if (!position || !url)
|
|
260
|
+
continue;
|
|
261
|
+
out.push({ position, title: title || url, url, description: snippet });
|
|
262
|
+
}
|
|
263
|
+
return out;
|
|
264
|
+
}
|
|
231
265
|
/**
|
|
232
266
|
* prepareSession + the on-chain createSession tx. Do this once, then run many
|
|
233
267
|
* jobs through the handle with `runJobOnSession`. Re-open when `expirySec`
|
|
@@ -235,7 +269,7 @@ function topicAsUint(hex) {
|
|
|
235
269
|
*/
|
|
236
270
|
export async function openSession(args) {
|
|
237
271
|
const { gateway, wallet, publicClient, network, model = "llama3-8b" } = args;
|
|
238
|
-
const prepared = await prepareSession(gateway, model);
|
|
272
|
+
const prepared = await prepareSession(gateway, model, args.requiredCapabilities ? { requiredCapabilities: args.requiredCapabilities } : undefined);
|
|
239
273
|
const fee = await estimateJobFee(network, model);
|
|
240
274
|
const createTx = await wallet.writeContract({
|
|
241
275
|
address: network.jobRegistry,
|
|
@@ -269,6 +303,7 @@ export async function openSession(args) {
|
|
|
269
303
|
worker: prepared.createSessionArgs.worker,
|
|
270
304
|
createTx,
|
|
271
305
|
expirySec: Number(prepared.createSessionArgs.expiry),
|
|
306
|
+
capabilities: prepared.workerCapabilities ?? [],
|
|
272
307
|
};
|
|
273
308
|
}
|
|
274
309
|
/**
|
|
@@ -277,7 +312,7 @@ export async function openSession(args) {
|
|
|
277
312
|
*/
|
|
278
313
|
export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
|
|
279
314
|
const { gateway, wallet, publicClient, network, sessionId, sessionKey, worker, fee, createTx } = session;
|
|
280
|
-
const { onChunk, onStage, jobCompletedTimeoutMs = 120000 } = opts;
|
|
315
|
+
const { onChunk, onStage, searchEnabled, jobCompletedTimeoutMs = 120000 } = opts;
|
|
281
316
|
const WS = pickWebSocket(opts.WebSocket);
|
|
282
317
|
const relayUrl = opts.relayUrl ?? `wss://relay.${network.id}.lightchain.ai/ws`;
|
|
283
318
|
// Shim so the job body below can keep referencing prepared.* unchanged.
|
|
@@ -327,6 +362,7 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
|
|
|
327
362
|
setTimeout(() => reject(new Error("relay WebSocket open timeout")), 20000);
|
|
328
363
|
});
|
|
329
364
|
const chunks = [];
|
|
365
|
+
const sources = [];
|
|
330
366
|
let streamDone = false;
|
|
331
367
|
let streamDoneAt = null;
|
|
332
368
|
const handleMessage = async (rawData) => {
|
|
@@ -344,6 +380,18 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
|
|
|
344
380
|
catch {
|
|
345
381
|
return;
|
|
346
382
|
}
|
|
383
|
+
// "metadata" carries web-search citations (sent before the answer stream).
|
|
384
|
+
if (frame.type === "metadata" && frame.payload) {
|
|
385
|
+
try {
|
|
386
|
+
const decoded = await decryptResponse(prepared.sessionKey, frame.payload);
|
|
387
|
+
for (const s of parseWebSearchSources(decoded))
|
|
388
|
+
sources.push(s);
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
/* ignore malformed metadata */
|
|
392
|
+
}
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
347
395
|
// "complete" marks end-of-stream (it may or may not carry a payload).
|
|
348
396
|
// Record it so the JobCompleted wait can stop promptly instead of polling
|
|
349
397
|
// the full grace window after the answer is already in hand.
|
|
@@ -382,8 +430,8 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
|
|
|
382
430
|
ws.addEventListener("message", (ev) => handleMessage(ev.data));
|
|
383
431
|
}
|
|
384
432
|
// 4. encrypt + upload prompt
|
|
385
|
-
onStage?.("Uploading prompt to chain...");
|
|
386
|
-
const promptHash = await submitPrompt(gateway, prepared.sessionKey, prompt);
|
|
433
|
+
onStage?.(searchEnabled ? "Searching the web + uploading prompt..." : "Uploading prompt to chain...");
|
|
434
|
+
const promptHash = await submitPrompt(gateway, prepared.sessionKey, prompt, searchEnabled ? { searchEnabled: true } : undefined);
|
|
387
435
|
// 5. submitJob on-chain
|
|
388
436
|
const submitTx = await wallet.writeContract({
|
|
389
437
|
address: network.jobRegistry,
|
|
@@ -485,6 +533,7 @@ export async function runJobOnSession(session, prompt, opts = {}, attempt = 1) {
|
|
|
485
533
|
jobId,
|
|
486
534
|
attempts: attempt,
|
|
487
535
|
stalled: [],
|
|
536
|
+
...(sources.length > 0 ? { sources } : {}),
|
|
488
537
|
};
|
|
489
538
|
}
|
|
490
539
|
/** One attempt = open a fresh session, then run one job through it. */
|
|
@@ -495,9 +544,11 @@ async function runOneAttempt(args, attempt) {
|
|
|
495
544
|
publicClient: args.publicClient,
|
|
496
545
|
network: args.network,
|
|
497
546
|
model: args.model,
|
|
547
|
+
...(args.searchEnabled ? { requiredCapabilities: ["search"] } : {}),
|
|
498
548
|
});
|
|
499
549
|
return runJobOnSession(session, args.prompt, {
|
|
500
550
|
onChunk: args.onChunk,
|
|
551
|
+
searchEnabled: args.searchEnabled,
|
|
501
552
|
jobCompletedTimeoutMs: args.jobCompletedTimeoutMs,
|
|
502
553
|
WebSocket: args.WebSocket,
|
|
503
554
|
relayUrl: args.relayUrl,
|
|
@@ -528,6 +579,8 @@ export class LightChatSession {
|
|
|
528
579
|
get sessionId() { return this.session.sessionId; }
|
|
529
580
|
get worker() { return this.session.worker; }
|
|
530
581
|
get model() { return this.session.model; }
|
|
582
|
+
/** Capabilities the bound worker advertises (e.g. ["search"]). */
|
|
583
|
+
get capabilities() { return this.session.capabilities; }
|
|
531
584
|
/** true once the on-chain session window has closed; re-open before sending. */
|
|
532
585
|
get expired() { return Date.now() / 1000 >= this.session.expirySec; }
|
|
533
586
|
send(prompt, opts = {}) {
|
|
@@ -711,6 +764,7 @@ export async function runInferenceWithKey(args) {
|
|
|
711
764
|
publicClient: publicClient,
|
|
712
765
|
network,
|
|
713
766
|
model: args.model,
|
|
767
|
+
searchEnabled: args.searchEnabled,
|
|
714
768
|
onChunk: args.onChunk,
|
|
715
769
|
maxRetries: args.maxRetries,
|
|
716
770
|
jobCompletedTimeoutMs: args.jobCompletedTimeoutMs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lightnode-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
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",
|