@querais/shared 0.2.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/LICENSE +21 -0
- package/dist/chain.d.ts +13764 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +31 -0
- package/dist/chain.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +45 -0
- package/dist/errors.js.map +1 -0
- package/dist/ids.d.ts +14 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +29 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/jobspec.d.ts +129 -0
- package/dist/jobspec.d.ts.map +1 -0
- package/dist/jobspec.js +59 -0
- package/dist/jobspec.js.map +1 -0
- package/dist/messages.d.ts +448 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +73 -0
- package/dist/messages.js.map +1 -0
- package/dist/model-manifest.d.ts +115 -0
- package/dist/model-manifest.d.ts.map +1 -0
- package/dist/model-manifest.js +77 -0
- package/dist/model-manifest.js.map +1 -0
- package/dist/openai.d.ts +140 -0
- package/dist/openai.d.ts.map +1 -0
- package/dist/openai.js +67 -0
- package/dist/openai.js.map +1 -0
- package/dist/pricing.d.ts +27 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +38 -0
- package/dist/pricing.js.map +1 -0
- package/dist/spending-cap.d.ts +101 -0
- package/dist/spending-cap.d.ts.map +1 -0
- package/dist/spending-cap.js +117 -0
- package/dist/spending-cap.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Gateway ↔ node wire protocol (JSON over WebSocket). Two discriminated unions:
|
|
4
|
+
* messages a node sends to the gateway, and messages the gateway sends to a node.
|
|
5
|
+
*
|
|
6
|
+
* Auth handshake: node connects → gateway sends `challenge` → node replies with
|
|
7
|
+
* `hello` containing a signature over the nonce (proving wallet control) → gateway
|
|
8
|
+
* verifies + checks the on-chain registry → `hello_ack`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const nodeModelOfferSchema: z.ZodObject<{
|
|
11
|
+
model: z.ZodString;
|
|
12
|
+
pricePerTokenWei: z.ZodString;
|
|
13
|
+
tokensPerSecond: z.ZodNumber;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
model: string;
|
|
16
|
+
pricePerTokenWei: string;
|
|
17
|
+
tokensPerSecond: number;
|
|
18
|
+
}, {
|
|
19
|
+
model: string;
|
|
20
|
+
pricePerTokenWei: string;
|
|
21
|
+
tokensPerSecond: number;
|
|
22
|
+
}>;
|
|
23
|
+
export type NodeModelOffer = z.infer<typeof nodeModelOfferSchema>;
|
|
24
|
+
export declare const challengeSchema: z.ZodObject<{
|
|
25
|
+
type: z.ZodLiteral<"challenge">;
|
|
26
|
+
nonce: z.ZodString;
|
|
27
|
+
}, "strip", z.ZodTypeAny, {
|
|
28
|
+
nonce: string;
|
|
29
|
+
type: "challenge";
|
|
30
|
+
}, {
|
|
31
|
+
nonce: string;
|
|
32
|
+
type: "challenge";
|
|
33
|
+
}>;
|
|
34
|
+
export declare const helloAckSchema: z.ZodObject<{
|
|
35
|
+
type: z.ZodLiteral<"hello_ack">;
|
|
36
|
+
ok: z.ZodBoolean;
|
|
37
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
type: "hello_ack";
|
|
40
|
+
ok: boolean;
|
|
41
|
+
reason?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
type: "hello_ack";
|
|
44
|
+
ok: boolean;
|
|
45
|
+
reason?: string | undefined;
|
|
46
|
+
}>;
|
|
47
|
+
export declare const jobAssignmentSchema: z.ZodObject<{
|
|
48
|
+
type: z.ZodLiteral<"job_assignment">;
|
|
49
|
+
spec: z.ZodObject<{
|
|
50
|
+
model: z.ZodString;
|
|
51
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
52
|
+
role: z.ZodEnum<["system", "user", "assistant"]>;
|
|
53
|
+
content: z.ZodString;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
role: "system" | "user" | "assistant";
|
|
56
|
+
content: string;
|
|
57
|
+
}, {
|
|
58
|
+
role: "system" | "user" | "assistant";
|
|
59
|
+
content: string;
|
|
60
|
+
}>, "many">;
|
|
61
|
+
maxTokens: z.ZodNumber;
|
|
62
|
+
temperature: z.ZodNumber;
|
|
63
|
+
stream: z.ZodBoolean;
|
|
64
|
+
requesterWallet: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
65
|
+
maxPricePerTokenWei: z.ZodString;
|
|
66
|
+
minReputation: z.ZodNumber;
|
|
67
|
+
createdAt: z.ZodNumber;
|
|
68
|
+
deadline: z.ZodNumber;
|
|
69
|
+
} & {
|
|
70
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
model: string;
|
|
73
|
+
messages: {
|
|
74
|
+
role: "system" | "user" | "assistant";
|
|
75
|
+
content: string;
|
|
76
|
+
}[];
|
|
77
|
+
temperature: number;
|
|
78
|
+
stream: boolean;
|
|
79
|
+
maxTokens: number;
|
|
80
|
+
requesterWallet: `0x${string}`;
|
|
81
|
+
maxPricePerTokenWei: string;
|
|
82
|
+
minReputation: number;
|
|
83
|
+
createdAt: number;
|
|
84
|
+
deadline: number;
|
|
85
|
+
jobId: `0x${string}`;
|
|
86
|
+
}, {
|
|
87
|
+
model: string;
|
|
88
|
+
messages: {
|
|
89
|
+
role: "system" | "user" | "assistant";
|
|
90
|
+
content: string;
|
|
91
|
+
}[];
|
|
92
|
+
temperature: number;
|
|
93
|
+
stream: boolean;
|
|
94
|
+
maxTokens: number;
|
|
95
|
+
requesterWallet: string;
|
|
96
|
+
maxPricePerTokenWei: string;
|
|
97
|
+
minReputation: number;
|
|
98
|
+
createdAt: number;
|
|
99
|
+
deadline: number;
|
|
100
|
+
jobId: string;
|
|
101
|
+
}>;
|
|
102
|
+
agreedPricePerTokenWei: z.ZodString;
|
|
103
|
+
}, "strip", z.ZodTypeAny, {
|
|
104
|
+
type: "job_assignment";
|
|
105
|
+
spec: {
|
|
106
|
+
model: string;
|
|
107
|
+
messages: {
|
|
108
|
+
role: "system" | "user" | "assistant";
|
|
109
|
+
content: string;
|
|
110
|
+
}[];
|
|
111
|
+
temperature: number;
|
|
112
|
+
stream: boolean;
|
|
113
|
+
maxTokens: number;
|
|
114
|
+
requesterWallet: `0x${string}`;
|
|
115
|
+
maxPricePerTokenWei: string;
|
|
116
|
+
minReputation: number;
|
|
117
|
+
createdAt: number;
|
|
118
|
+
deadline: number;
|
|
119
|
+
jobId: `0x${string}`;
|
|
120
|
+
};
|
|
121
|
+
agreedPricePerTokenWei: string;
|
|
122
|
+
}, {
|
|
123
|
+
type: "job_assignment";
|
|
124
|
+
spec: {
|
|
125
|
+
model: string;
|
|
126
|
+
messages: {
|
|
127
|
+
role: "system" | "user" | "assistant";
|
|
128
|
+
content: string;
|
|
129
|
+
}[];
|
|
130
|
+
temperature: number;
|
|
131
|
+
stream: boolean;
|
|
132
|
+
maxTokens: number;
|
|
133
|
+
requesterWallet: string;
|
|
134
|
+
maxPricePerTokenWei: string;
|
|
135
|
+
minReputation: number;
|
|
136
|
+
createdAt: number;
|
|
137
|
+
deadline: number;
|
|
138
|
+
jobId: string;
|
|
139
|
+
};
|
|
140
|
+
agreedPricePerTokenWei: string;
|
|
141
|
+
}>;
|
|
142
|
+
export declare const gatewayToNodeSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
143
|
+
type: z.ZodLiteral<"challenge">;
|
|
144
|
+
nonce: z.ZodString;
|
|
145
|
+
}, "strip", z.ZodTypeAny, {
|
|
146
|
+
nonce: string;
|
|
147
|
+
type: "challenge";
|
|
148
|
+
}, {
|
|
149
|
+
nonce: string;
|
|
150
|
+
type: "challenge";
|
|
151
|
+
}>, z.ZodObject<{
|
|
152
|
+
type: z.ZodLiteral<"hello_ack">;
|
|
153
|
+
ok: z.ZodBoolean;
|
|
154
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
155
|
+
}, "strip", z.ZodTypeAny, {
|
|
156
|
+
type: "hello_ack";
|
|
157
|
+
ok: boolean;
|
|
158
|
+
reason?: string | undefined;
|
|
159
|
+
}, {
|
|
160
|
+
type: "hello_ack";
|
|
161
|
+
ok: boolean;
|
|
162
|
+
reason?: string | undefined;
|
|
163
|
+
}>, z.ZodObject<{
|
|
164
|
+
type: z.ZodLiteral<"job_assignment">;
|
|
165
|
+
spec: z.ZodObject<{
|
|
166
|
+
model: z.ZodString;
|
|
167
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
168
|
+
role: z.ZodEnum<["system", "user", "assistant"]>;
|
|
169
|
+
content: z.ZodString;
|
|
170
|
+
}, "strip", z.ZodTypeAny, {
|
|
171
|
+
role: "system" | "user" | "assistant";
|
|
172
|
+
content: string;
|
|
173
|
+
}, {
|
|
174
|
+
role: "system" | "user" | "assistant";
|
|
175
|
+
content: string;
|
|
176
|
+
}>, "many">;
|
|
177
|
+
maxTokens: z.ZodNumber;
|
|
178
|
+
temperature: z.ZodNumber;
|
|
179
|
+
stream: z.ZodBoolean;
|
|
180
|
+
requesterWallet: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
181
|
+
maxPricePerTokenWei: z.ZodString;
|
|
182
|
+
minReputation: z.ZodNumber;
|
|
183
|
+
createdAt: z.ZodNumber;
|
|
184
|
+
deadline: z.ZodNumber;
|
|
185
|
+
} & {
|
|
186
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
187
|
+
}, "strip", z.ZodTypeAny, {
|
|
188
|
+
model: string;
|
|
189
|
+
messages: {
|
|
190
|
+
role: "system" | "user" | "assistant";
|
|
191
|
+
content: string;
|
|
192
|
+
}[];
|
|
193
|
+
temperature: number;
|
|
194
|
+
stream: boolean;
|
|
195
|
+
maxTokens: number;
|
|
196
|
+
requesterWallet: `0x${string}`;
|
|
197
|
+
maxPricePerTokenWei: string;
|
|
198
|
+
minReputation: number;
|
|
199
|
+
createdAt: number;
|
|
200
|
+
deadline: number;
|
|
201
|
+
jobId: `0x${string}`;
|
|
202
|
+
}, {
|
|
203
|
+
model: string;
|
|
204
|
+
messages: {
|
|
205
|
+
role: "system" | "user" | "assistant";
|
|
206
|
+
content: string;
|
|
207
|
+
}[];
|
|
208
|
+
temperature: number;
|
|
209
|
+
stream: boolean;
|
|
210
|
+
maxTokens: number;
|
|
211
|
+
requesterWallet: string;
|
|
212
|
+
maxPricePerTokenWei: string;
|
|
213
|
+
minReputation: number;
|
|
214
|
+
createdAt: number;
|
|
215
|
+
deadline: number;
|
|
216
|
+
jobId: string;
|
|
217
|
+
}>;
|
|
218
|
+
agreedPricePerTokenWei: z.ZodString;
|
|
219
|
+
}, "strip", z.ZodTypeAny, {
|
|
220
|
+
type: "job_assignment";
|
|
221
|
+
spec: {
|
|
222
|
+
model: string;
|
|
223
|
+
messages: {
|
|
224
|
+
role: "system" | "user" | "assistant";
|
|
225
|
+
content: string;
|
|
226
|
+
}[];
|
|
227
|
+
temperature: number;
|
|
228
|
+
stream: boolean;
|
|
229
|
+
maxTokens: number;
|
|
230
|
+
requesterWallet: `0x${string}`;
|
|
231
|
+
maxPricePerTokenWei: string;
|
|
232
|
+
minReputation: number;
|
|
233
|
+
createdAt: number;
|
|
234
|
+
deadline: number;
|
|
235
|
+
jobId: `0x${string}`;
|
|
236
|
+
};
|
|
237
|
+
agreedPricePerTokenWei: string;
|
|
238
|
+
}, {
|
|
239
|
+
type: "job_assignment";
|
|
240
|
+
spec: {
|
|
241
|
+
model: string;
|
|
242
|
+
messages: {
|
|
243
|
+
role: "system" | "user" | "assistant";
|
|
244
|
+
content: string;
|
|
245
|
+
}[];
|
|
246
|
+
temperature: number;
|
|
247
|
+
stream: boolean;
|
|
248
|
+
maxTokens: number;
|
|
249
|
+
requesterWallet: string;
|
|
250
|
+
maxPricePerTokenWei: string;
|
|
251
|
+
minReputation: number;
|
|
252
|
+
createdAt: number;
|
|
253
|
+
deadline: number;
|
|
254
|
+
jobId: string;
|
|
255
|
+
};
|
|
256
|
+
agreedPricePerTokenWei: string;
|
|
257
|
+
}>]>;
|
|
258
|
+
export type GatewayToNode = z.infer<typeof gatewayToNodeSchema>;
|
|
259
|
+
export declare const nodeHelloSchema: z.ZodObject<{
|
|
260
|
+
type: z.ZodLiteral<"hello">;
|
|
261
|
+
nodeId: z.ZodString;
|
|
262
|
+
wallet: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
263
|
+
nonce: z.ZodString;
|
|
264
|
+
signature: z.ZodString;
|
|
265
|
+
models: z.ZodArray<z.ZodObject<{
|
|
266
|
+
model: z.ZodString;
|
|
267
|
+
pricePerTokenWei: z.ZodString;
|
|
268
|
+
tokensPerSecond: z.ZodNumber;
|
|
269
|
+
}, "strip", z.ZodTypeAny, {
|
|
270
|
+
model: string;
|
|
271
|
+
pricePerTokenWei: string;
|
|
272
|
+
tokensPerSecond: number;
|
|
273
|
+
}, {
|
|
274
|
+
model: string;
|
|
275
|
+
pricePerTokenWei: string;
|
|
276
|
+
tokensPerSecond: number;
|
|
277
|
+
}>, "many">;
|
|
278
|
+
/** Slice 9 (additive): model → blob digest, so a manifest-enforcing gateway can
|
|
279
|
+
* verify offers at handshake. Absent on pre-Slice-9 daemons — those still join,
|
|
280
|
+
* but any model the manifest pins is dropped from their offers. */
|
|
281
|
+
modelDigests: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
282
|
+
}, "strip", z.ZodTypeAny, {
|
|
283
|
+
nonce: string;
|
|
284
|
+
type: "hello";
|
|
285
|
+
signature: string;
|
|
286
|
+
models: {
|
|
287
|
+
model: string;
|
|
288
|
+
pricePerTokenWei: string;
|
|
289
|
+
tokensPerSecond: number;
|
|
290
|
+
}[];
|
|
291
|
+
nodeId: string;
|
|
292
|
+
wallet: `0x${string}`;
|
|
293
|
+
modelDigests?: Record<string, string> | undefined;
|
|
294
|
+
}, {
|
|
295
|
+
nonce: string;
|
|
296
|
+
type: "hello";
|
|
297
|
+
signature: string;
|
|
298
|
+
models: {
|
|
299
|
+
model: string;
|
|
300
|
+
pricePerTokenWei: string;
|
|
301
|
+
tokensPerSecond: number;
|
|
302
|
+
}[];
|
|
303
|
+
nodeId: string;
|
|
304
|
+
wallet: string;
|
|
305
|
+
modelDigests?: Record<string, string> | undefined;
|
|
306
|
+
}>;
|
|
307
|
+
export declare const tokenChunkSchema: z.ZodObject<{
|
|
308
|
+
type: z.ZodLiteral<"token">;
|
|
309
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
310
|
+
content: z.ZodString;
|
|
311
|
+
}, "strip", z.ZodTypeAny, {
|
|
312
|
+
type: "token";
|
|
313
|
+
content: string;
|
|
314
|
+
jobId: `0x${string}`;
|
|
315
|
+
}, {
|
|
316
|
+
type: "token";
|
|
317
|
+
content: string;
|
|
318
|
+
jobId: string;
|
|
319
|
+
}>;
|
|
320
|
+
export declare const completionReportSchema: z.ZodObject<{
|
|
321
|
+
type: z.ZodLiteral<"completion">;
|
|
322
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
323
|
+
tokenCount: z.ZodNumber;
|
|
324
|
+
finishReason: z.ZodEnum<["stop", "length", "error"]>;
|
|
325
|
+
resultHash: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
326
|
+
}, "strip", z.ZodTypeAny, {
|
|
327
|
+
type: "completion";
|
|
328
|
+
jobId: `0x${string}`;
|
|
329
|
+
tokenCount: number;
|
|
330
|
+
finishReason: "length" | "stop" | "error";
|
|
331
|
+
resultHash: `0x${string}`;
|
|
332
|
+
}, {
|
|
333
|
+
type: "completion";
|
|
334
|
+
jobId: string;
|
|
335
|
+
tokenCount: number;
|
|
336
|
+
finishReason: "length" | "stop" | "error";
|
|
337
|
+
resultHash: string;
|
|
338
|
+
}>;
|
|
339
|
+
export declare const jobErrorSchema: z.ZodObject<{
|
|
340
|
+
type: z.ZodLiteral<"job_error">;
|
|
341
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
342
|
+
message: z.ZodString;
|
|
343
|
+
}, "strip", z.ZodTypeAny, {
|
|
344
|
+
type: "job_error";
|
|
345
|
+
message: string;
|
|
346
|
+
jobId: `0x${string}`;
|
|
347
|
+
}, {
|
|
348
|
+
type: "job_error";
|
|
349
|
+
message: string;
|
|
350
|
+
jobId: string;
|
|
351
|
+
}>;
|
|
352
|
+
export declare const nodeToGatewaySchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
353
|
+
type: z.ZodLiteral<"hello">;
|
|
354
|
+
nodeId: z.ZodString;
|
|
355
|
+
wallet: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
356
|
+
nonce: z.ZodString;
|
|
357
|
+
signature: z.ZodString;
|
|
358
|
+
models: z.ZodArray<z.ZodObject<{
|
|
359
|
+
model: z.ZodString;
|
|
360
|
+
pricePerTokenWei: z.ZodString;
|
|
361
|
+
tokensPerSecond: z.ZodNumber;
|
|
362
|
+
}, "strip", z.ZodTypeAny, {
|
|
363
|
+
model: string;
|
|
364
|
+
pricePerTokenWei: string;
|
|
365
|
+
tokensPerSecond: number;
|
|
366
|
+
}, {
|
|
367
|
+
model: string;
|
|
368
|
+
pricePerTokenWei: string;
|
|
369
|
+
tokensPerSecond: number;
|
|
370
|
+
}>, "many">;
|
|
371
|
+
/** Slice 9 (additive): model → blob digest, so a manifest-enforcing gateway can
|
|
372
|
+
* verify offers at handshake. Absent on pre-Slice-9 daemons — those still join,
|
|
373
|
+
* but any model the manifest pins is dropped from their offers. */
|
|
374
|
+
modelDigests: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
375
|
+
}, "strip", z.ZodTypeAny, {
|
|
376
|
+
nonce: string;
|
|
377
|
+
type: "hello";
|
|
378
|
+
signature: string;
|
|
379
|
+
models: {
|
|
380
|
+
model: string;
|
|
381
|
+
pricePerTokenWei: string;
|
|
382
|
+
tokensPerSecond: number;
|
|
383
|
+
}[];
|
|
384
|
+
nodeId: string;
|
|
385
|
+
wallet: `0x${string}`;
|
|
386
|
+
modelDigests?: Record<string, string> | undefined;
|
|
387
|
+
}, {
|
|
388
|
+
nonce: string;
|
|
389
|
+
type: "hello";
|
|
390
|
+
signature: string;
|
|
391
|
+
models: {
|
|
392
|
+
model: string;
|
|
393
|
+
pricePerTokenWei: string;
|
|
394
|
+
tokensPerSecond: number;
|
|
395
|
+
}[];
|
|
396
|
+
nodeId: string;
|
|
397
|
+
wallet: string;
|
|
398
|
+
modelDigests?: Record<string, string> | undefined;
|
|
399
|
+
}>, z.ZodObject<{
|
|
400
|
+
type: z.ZodLiteral<"token">;
|
|
401
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
402
|
+
content: z.ZodString;
|
|
403
|
+
}, "strip", z.ZodTypeAny, {
|
|
404
|
+
type: "token";
|
|
405
|
+
content: string;
|
|
406
|
+
jobId: `0x${string}`;
|
|
407
|
+
}, {
|
|
408
|
+
type: "token";
|
|
409
|
+
content: string;
|
|
410
|
+
jobId: string;
|
|
411
|
+
}>, z.ZodObject<{
|
|
412
|
+
type: z.ZodLiteral<"completion">;
|
|
413
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
414
|
+
tokenCount: z.ZodNumber;
|
|
415
|
+
finishReason: z.ZodEnum<["stop", "length", "error"]>;
|
|
416
|
+
resultHash: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
417
|
+
}, "strip", z.ZodTypeAny, {
|
|
418
|
+
type: "completion";
|
|
419
|
+
jobId: `0x${string}`;
|
|
420
|
+
tokenCount: number;
|
|
421
|
+
finishReason: "length" | "stop" | "error";
|
|
422
|
+
resultHash: `0x${string}`;
|
|
423
|
+
}, {
|
|
424
|
+
type: "completion";
|
|
425
|
+
jobId: string;
|
|
426
|
+
tokenCount: number;
|
|
427
|
+
finishReason: "length" | "stop" | "error";
|
|
428
|
+
resultHash: string;
|
|
429
|
+
}>, z.ZodObject<{
|
|
430
|
+
type: z.ZodLiteral<"job_error">;
|
|
431
|
+
jobId: z.ZodEffects<z.ZodString, `0x${string}`, string>;
|
|
432
|
+
message: z.ZodString;
|
|
433
|
+
}, "strip", z.ZodTypeAny, {
|
|
434
|
+
type: "job_error";
|
|
435
|
+
message: string;
|
|
436
|
+
jobId: `0x${string}`;
|
|
437
|
+
}, {
|
|
438
|
+
type: "job_error";
|
|
439
|
+
message: string;
|
|
440
|
+
jobId: string;
|
|
441
|
+
}>]>;
|
|
442
|
+
export type NodeToGateway = z.infer<typeof nodeToGatewaySchema>;
|
|
443
|
+
export type NodeHello = z.infer<typeof nodeHelloSchema>;
|
|
444
|
+
export type JobAssignment = z.infer<typeof jobAssignmentSchema>;
|
|
445
|
+
export type TokenChunk = z.infer<typeof tokenChunkSchema>;
|
|
446
|
+
export type CompletionReport = z.infer<typeof completionReportSchema>;
|
|
447
|
+
export type JobErrorMessage = z.infer<typeof jobErrorSchema>;
|
|
448
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB;;;;;;;GAOG;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAI/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE,eAAO,MAAM,eAAe;;;;;;;;;EAG1B,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;EAIzB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI9B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAIhE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;IAO1B;;wEAEoE;;;;;;;;;;;;;;;;;;;;;;;;;;EAEpE,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;EAI3B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;EAMjC,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;EAIzB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;IA1B9B;;wEAEoE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BpE,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { addressSchema, bytes32Schema, decimalStringSchema, identifiedJobSpecSchema, } from './jobspec.js';
|
|
3
|
+
import { MODEL_DIGEST_REGEX } from './model-manifest.js';
|
|
4
|
+
/**
|
|
5
|
+
* Gateway ↔ node wire protocol (JSON over WebSocket). Two discriminated unions:
|
|
6
|
+
* messages a node sends to the gateway, and messages the gateway sends to a node.
|
|
7
|
+
*
|
|
8
|
+
* Auth handshake: node connects → gateway sends `challenge` → node replies with
|
|
9
|
+
* `hello` containing a signature over the nonce (proving wallet control) → gateway
|
|
10
|
+
* verifies + checks the on-chain registry → `hello_ack`.
|
|
11
|
+
*/
|
|
12
|
+
export const nodeModelOfferSchema = z.object({
|
|
13
|
+
model: z.string().min(1),
|
|
14
|
+
pricePerTokenWei: decimalStringSchema,
|
|
15
|
+
tokensPerSecond: z.number().nonnegative(),
|
|
16
|
+
});
|
|
17
|
+
// ── Gateway → Node ─────────────────────────────────────────────────────────────
|
|
18
|
+
export const challengeSchema = z.object({
|
|
19
|
+
type: z.literal('challenge'),
|
|
20
|
+
nonce: z.string().min(1),
|
|
21
|
+
});
|
|
22
|
+
export const helloAckSchema = z.object({
|
|
23
|
+
type: z.literal('hello_ack'),
|
|
24
|
+
ok: z.boolean(),
|
|
25
|
+
reason: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
export const jobAssignmentSchema = z.object({
|
|
28
|
+
type: z.literal('job_assignment'),
|
|
29
|
+
spec: identifiedJobSpecSchema,
|
|
30
|
+
agreedPricePerTokenWei: decimalStringSchema,
|
|
31
|
+
});
|
|
32
|
+
export const gatewayToNodeSchema = z.discriminatedUnion('type', [
|
|
33
|
+
challengeSchema,
|
|
34
|
+
helloAckSchema,
|
|
35
|
+
jobAssignmentSchema,
|
|
36
|
+
]);
|
|
37
|
+
// ── Node → Gateway ───────────────────────────────────────────────────────────
|
|
38
|
+
export const nodeHelloSchema = z.object({
|
|
39
|
+
type: z.literal('hello'),
|
|
40
|
+
nodeId: z.string().min(1),
|
|
41
|
+
wallet: addressSchema,
|
|
42
|
+
nonce: z.string().min(1),
|
|
43
|
+
signature: z.string().min(1),
|
|
44
|
+
models: z.array(nodeModelOfferSchema).min(1),
|
|
45
|
+
/** Slice 9 (additive): model → blob digest, so a manifest-enforcing gateway can
|
|
46
|
+
* verify offers at handshake. Absent on pre-Slice-9 daemons — those still join,
|
|
47
|
+
* but any model the manifest pins is dropped from their offers. */
|
|
48
|
+
modelDigests: z.record(z.string().min(1), z.string().regex(MODEL_DIGEST_REGEX)).optional(),
|
|
49
|
+
});
|
|
50
|
+
export const tokenChunkSchema = z.object({
|
|
51
|
+
type: z.literal('token'),
|
|
52
|
+
jobId: bytes32Schema,
|
|
53
|
+
content: z.string(),
|
|
54
|
+
});
|
|
55
|
+
export const completionReportSchema = z.object({
|
|
56
|
+
type: z.literal('completion'),
|
|
57
|
+
jobId: bytes32Schema,
|
|
58
|
+
tokenCount: z.number().int().nonnegative(),
|
|
59
|
+
finishReason: z.enum(['stop', 'length', 'error']),
|
|
60
|
+
resultHash: bytes32Schema,
|
|
61
|
+
});
|
|
62
|
+
export const jobErrorSchema = z.object({
|
|
63
|
+
type: z.literal('job_error'),
|
|
64
|
+
jobId: bytes32Schema,
|
|
65
|
+
message: z.string(),
|
|
66
|
+
});
|
|
67
|
+
export const nodeToGatewaySchema = z.discriminatedUnion('type', [
|
|
68
|
+
nodeHelloSchema,
|
|
69
|
+
tokenChunkSchema,
|
|
70
|
+
completionReportSchema,
|
|
71
|
+
jobErrorSchema,
|
|
72
|
+
]);
|
|
73
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Signed model manifest — the operator's off-chain statement of which model
|
|
3
|
+
* binaries (by Ollama sha256 digest) count as "the real model" on this network.
|
|
4
|
+
*
|
|
5
|
+
* Lives in shared because both sides of the trust relationship consume it:
|
|
6
|
+
* the gateway loads + signs the manifest at boot and enforces it at node
|
|
7
|
+
* handshake; the node daemon fetches it from `GET /v1/models/manifest` and
|
|
8
|
+
* verifies the signature against the gateway's settler address (which it
|
|
9
|
+
* already learns from `/v1/credit/info`) before trusting the digests.
|
|
10
|
+
*
|
|
11
|
+
* Signing is EIP-191 (`personal_sign`) over a canonical JSON form — model keys
|
|
12
|
+
* sorted, entry fields in fixed order — so any holder of the manifest can
|
|
13
|
+
* re-derive the exact signed bytes and verify offline. No contract involved
|
|
14
|
+
* (Slice 9 decision: exclusion, not punishment — a mismatched model is simply
|
|
15
|
+
* not served; slashing stays with the dispute system).
|
|
16
|
+
*/
|
|
17
|
+
import { type Address, type Hex } from 'viem';
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
/** Ollama-style digest of the model blob: "sha256:" + 64 lowercase hex chars. */
|
|
20
|
+
export declare const MODEL_DIGEST_REGEX: RegExp;
|
|
21
|
+
export declare const modelManifestEntrySchema: z.ZodObject<{
|
|
22
|
+
digest: z.ZodString;
|
|
23
|
+
/** Free-form operator note ("gemma3:4b pulled 2026-06-01"); not enforced. */
|
|
24
|
+
note: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
digest: string;
|
|
27
|
+
note?: string | undefined;
|
|
28
|
+
}, {
|
|
29
|
+
digest: string;
|
|
30
|
+
note?: string | undefined;
|
|
31
|
+
}>;
|
|
32
|
+
export type ModelManifestEntry = z.infer<typeof modelManifestEntrySchema>;
|
|
33
|
+
/** The unsigned manifest body — what the operator authors as a JSON file. */
|
|
34
|
+
export declare const modelManifestSchema: z.ZodObject<{
|
|
35
|
+
models: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
36
|
+
digest: z.ZodString;
|
|
37
|
+
/** Free-form operator note ("gemma3:4b pulled 2026-06-01"); not enforced. */
|
|
38
|
+
note: z.ZodOptional<z.ZodString>;
|
|
39
|
+
}, "strip", z.ZodTypeAny, {
|
|
40
|
+
digest: string;
|
|
41
|
+
note?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
digest: string;
|
|
44
|
+
note?: string | undefined;
|
|
45
|
+
}>>;
|
|
46
|
+
}, "strict", z.ZodTypeAny, {
|
|
47
|
+
models: Record<string, {
|
|
48
|
+
digest: string;
|
|
49
|
+
note?: string | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
}, {
|
|
52
|
+
models: Record<string, {
|
|
53
|
+
digest: string;
|
|
54
|
+
note?: string | undefined;
|
|
55
|
+
}>;
|
|
56
|
+
}>;
|
|
57
|
+
export type ModelManifest = z.infer<typeof modelManifestSchema>;
|
|
58
|
+
/** Wire form served by `GET /v1/models/manifest` (and verified by daemons). */
|
|
59
|
+
export declare const signedModelManifestSchema: z.ZodObject<{
|
|
60
|
+
models: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
61
|
+
digest: z.ZodString;
|
|
62
|
+
/** Free-form operator note ("gemma3:4b pulled 2026-06-01"); not enforced. */
|
|
63
|
+
note: z.ZodOptional<z.ZodString>;
|
|
64
|
+
}, "strip", z.ZodTypeAny, {
|
|
65
|
+
digest: string;
|
|
66
|
+
note?: string | undefined;
|
|
67
|
+
}, {
|
|
68
|
+
digest: string;
|
|
69
|
+
note?: string | undefined;
|
|
70
|
+
}>>;
|
|
71
|
+
signer: z.ZodString;
|
|
72
|
+
signature: z.ZodString;
|
|
73
|
+
}, "strip", z.ZodTypeAny, {
|
|
74
|
+
signature: string;
|
|
75
|
+
models: Record<string, {
|
|
76
|
+
digest: string;
|
|
77
|
+
note?: string | undefined;
|
|
78
|
+
}>;
|
|
79
|
+
signer: string;
|
|
80
|
+
}, {
|
|
81
|
+
signature: string;
|
|
82
|
+
models: Record<string, {
|
|
83
|
+
digest: string;
|
|
84
|
+
note?: string | undefined;
|
|
85
|
+
}>;
|
|
86
|
+
signer: string;
|
|
87
|
+
}>;
|
|
88
|
+
export interface SignedModelManifest {
|
|
89
|
+
models: Record<string, ModelManifestEntry>;
|
|
90
|
+
/** The gateway wallet that signed — daemons check it equals the settler. */
|
|
91
|
+
signer: Address;
|
|
92
|
+
/** EIP-191 signature over `canonicalModelManifestJson(models)`. */
|
|
93
|
+
signature: Hex;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The exact byte string that gets signed: `{"models":{...}}` with model keys
|
|
97
|
+
* sorted and entry fields in fixed (digest, note) order. Deterministic across
|
|
98
|
+
* runtimes, so gateway and daemon always derive identical bytes.
|
|
99
|
+
*/
|
|
100
|
+
export declare function canonicalModelManifestJson(models: Record<string, ModelManifestEntry>): string;
|
|
101
|
+
/** Minimal signer shape — viem LocalAccount and (account-bound) WalletClient both satisfy it. */
|
|
102
|
+
export interface ManifestSigner {
|
|
103
|
+
signMessage(args: {
|
|
104
|
+
message: string;
|
|
105
|
+
}): Promise<Hex>;
|
|
106
|
+
}
|
|
107
|
+
/** Sign the manifest with the gateway key (done once at boot). */
|
|
108
|
+
export declare function signModelManifest(signer: ManifestSigner, signerAddress: Address, models: Record<string, ModelManifestEntry>): Promise<SignedModelManifest>;
|
|
109
|
+
/**
|
|
110
|
+
* Verify a fetched manifest: recover the EIP-191 signer from the canonical
|
|
111
|
+
* JSON and compare to the claimed `signer`. Pure (no RPC); returns false on
|
|
112
|
+
* any malformed input rather than throwing.
|
|
113
|
+
*/
|
|
114
|
+
export declare function verifyModelManifest(manifest: SignedModelManifest): Promise<boolean>;
|
|
115
|
+
//# sourceMappingURL=model-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-manifest.d.ts","sourceRoot":"","sources":["../src/model-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAyB,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AACrE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,QAA0B,CAAC;AAE1D,eAAO,MAAM,wBAAwB;;IAEnC,6EAA6E;;;;;;;;EAE7E,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB;;;QAP9B,6EAA6E;;;;;;;;;;;;;;;;;;;EAWpE,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAIhE,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB;;;QAlBpC,6EAA6E;;;;;;;;;;;;;;;;;;;;;;;;;EAsB7E,CAAC;AAEH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC3C,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,MAAM,CAU7F;AAED,iGAAiG;AACjG,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CACtD;AAED,kEAAkE;AAClE,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,OAAO,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GACzC,OAAO,CAAC,mBAAmB,CAAC,CAG9B;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAUzF"}
|