@halot/sdk 1.0.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.
Files changed (60) hide show
  1. package/README.md +243 -0
  2. package/dist/auth/actor.d.ts +17 -0
  3. package/dist/auth/actor.js +33 -0
  4. package/dist/auth/attestation.d.ts +24 -0
  5. package/dist/auth/attestation.js +47 -0
  6. package/dist/client/halot-client.d.ts +37 -0
  7. package/dist/client/halot-client.js +89 -0
  8. package/dist/client/index.d.ts +2 -0
  9. package/dist/client/index.js +5 -0
  10. package/dist/config.d.ts +2 -0
  11. package/dist/config.js +11 -0
  12. package/dist/index.d.ts +26 -0
  13. package/dist/index.js +43 -0
  14. package/dist/middleware/aggregator-client.d.ts +8 -0
  15. package/dist/middleware/aggregator-client.js +49 -0
  16. package/dist/middleware/halot.d.ts +4 -0
  17. package/dist/middleware/halot.js +142 -0
  18. package/dist/middleware/index.d.ts +2 -0
  19. package/dist/middleware/index.js +5 -0
  20. package/dist/middleware/types.d.ts +45 -0
  21. package/dist/middleware/types.js +2 -0
  22. package/dist/types/common.d.ts +90 -0
  23. package/dist/types/common.js +66 -0
  24. package/dist/types/job.d.ts +232 -0
  25. package/dist/types/job.js +125 -0
  26. package/dist/types/provider.d.ts +160 -0
  27. package/dist/types/provider.js +45 -0
  28. package/dist/types/quote.d.ts +43 -0
  29. package/dist/types/quote.js +31 -0
  30. package/dist/types/requester.d.ts +15 -0
  31. package/dist/types/requester.js +15 -0
  32. package/dist/types/service.d.ts +140 -0
  33. package/dist/types/service.js +48 -0
  34. package/dist/types/verifier.d.ts +144 -0
  35. package/dist/types/verifier.js +78 -0
  36. package/dist/types/x402.d.ts +31 -0
  37. package/dist/types/x402.js +27 -0
  38. package/dist/utils/amount.d.ts +2 -0
  39. package/dist/utils/amount.js +11 -0
  40. package/dist/utils/artifacts.d.ts +42 -0
  41. package/dist/utils/artifacts.js +378 -0
  42. package/dist/utils/category.d.ts +4 -0
  43. package/dist/utils/category.js +25 -0
  44. package/dist/utils/date.d.ts +2 -0
  45. package/dist/utils/date.js +10 -0
  46. package/dist/utils/hash.d.ts +4 -0
  47. package/dist/utils/hash.js +27 -0
  48. package/dist/utils/id.d.ts +1 -0
  49. package/dist/utils/id.js +7 -0
  50. package/dist/utils/json-file.d.ts +3 -0
  51. package/dist/utils/json-file.js +20 -0
  52. package/dist/utils/schema.d.ts +5 -0
  53. package/dist/utils/schema.js +66 -0
  54. package/dist/x402/payment.d.ts +11 -0
  55. package/dist/x402/payment.js +68 -0
  56. package/dist/zero-g/compute.d.ts +53 -0
  57. package/dist/zero-g/compute.js +249 -0
  58. package/dist/zero-g/storage.d.ts +28 -0
  59. package/dist/zero-g/storage.js +93 -0
  60. package/package.json +66 -0
@@ -0,0 +1,53 @@
1
+ import { Decision } from '../types/common';
2
+ import { TeeProof } from '../types/job';
3
+ import { Service } from '../types/service';
4
+ export type ComputeEvaluationInput = {
5
+ jobHash: string;
6
+ resultHash: string;
7
+ input: unknown;
8
+ result: unknown;
9
+ service: Service;
10
+ providerAddress?: string;
11
+ systemPrompt?: string;
12
+ promptTemplate?: string;
13
+ outputSchema?: Record<string, string>;
14
+ maxTokens?: number;
15
+ temperature?: number;
16
+ model?: string;
17
+ };
18
+ export type ComputeEvaluationOutput = {
19
+ decision: Decision;
20
+ confidence: number;
21
+ reason: string;
22
+ failedCriteria: string[];
23
+ teeVerified: boolean;
24
+ teeProof: TeeProof;
25
+ };
26
+ export type ZeroGComputeOptions = {
27
+ rpcUrl?: string;
28
+ privateKey?: string;
29
+ providerAddress?: string;
30
+ ledgerContractAddress?: string;
31
+ inferenceContractAddress?: string;
32
+ fineTuningContractAddress?: string;
33
+ fetchImplementation?: typeof fetch;
34
+ };
35
+ export declare class ZeroGComputeService {
36
+ private readonly rpcUrl?;
37
+ private readonly privateKey?;
38
+ private readonly providerAddress?;
39
+ private readonly ledgerContractAddress?;
40
+ private readonly inferenceContractAddress?;
41
+ private readonly fineTuningContractAddress?;
42
+ private readonly fetchImplementation;
43
+ constructor(options?: ZeroGComputeOptions);
44
+ evaluate(input: ComputeEvaluationInput): Promise<ComputeEvaluationOutput>;
45
+ private evaluateWithZeroG;
46
+ private renderPrompt;
47
+ private buildUserContent;
48
+ private extractMessageContent;
49
+ private parseEvaluationResponse;
50
+ private extractJson;
51
+ private parseDecision;
52
+ private createWallet;
53
+ }
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZeroGComputeService = void 0;
4
+ const _0g_serving_broker_1 = require("@0glabs/0g-serving-broker");
5
+ const ethers_1 = require("ethers");
6
+ const artifacts_1 = require("../utils/artifacts");
7
+ const hash_1 = require("../utils/hash");
8
+ const id_1 = require("../utils/id");
9
+ class ZeroGComputeService {
10
+ rpcUrl;
11
+ privateKey;
12
+ providerAddress;
13
+ ledgerContractAddress;
14
+ inferenceContractAddress;
15
+ fineTuningContractAddress;
16
+ fetchImplementation;
17
+ constructor(options = {}) {
18
+ this.rpcUrl = options.rpcUrl;
19
+ this.privateKey = options.privateKey;
20
+ this.providerAddress = options.providerAddress;
21
+ this.ledgerContractAddress = options.ledgerContractAddress;
22
+ this.inferenceContractAddress = options.inferenceContractAddress;
23
+ this.fineTuningContractAddress = options.fineTuningContractAddress;
24
+ this.fetchImplementation = options.fetchImplementation ?? fetch;
25
+ }
26
+ async evaluate(input) {
27
+ return this.evaluateWithZeroG(input);
28
+ }
29
+ async evaluateWithZeroG(input) {
30
+ const providerAddress = (0, ethers_1.getAddress)(input.providerAddress ?? this.providerAddress ?? '');
31
+ const wallet = this.createWallet();
32
+ const broker = await (0, _0g_serving_broker_1.createZGComputeNetworkBroker)(wallet, this.ledgerContractAddress, this.inferenceContractAddress, this.fineTuningContractAddress);
33
+ if (!(await broker.inference.acknowledged(providerAddress))) {
34
+ await broker.inference.acknowledgeProviderSigner(providerAddress);
35
+ }
36
+ const { endpoint, model } = await broker.inference.getServiceMetadata(providerAddress);
37
+ const artifacts = await (0, artifacts_1.resolveImageArtifacts)(input.input, input.result, {
38
+ fetchImplementation: this.fetchImplementation,
39
+ outputFormat: input.service.output.format,
40
+ });
41
+ const prompt = this.renderPrompt(input, artifacts);
42
+ const requestBody = {
43
+ model: input.model ?? model,
44
+ messages: [
45
+ {
46
+ role: 'system',
47
+ content: input.systemPrompt ?? 'You are an impartial evaluator. Return only valid JSON.',
48
+ },
49
+ {
50
+ role: 'user',
51
+ content: this.buildUserContent(prompt, artifacts),
52
+ },
53
+ ],
54
+ temperature: input.temperature ?? 0,
55
+ max_tokens: input.maxTokens ?? 1024,
56
+ };
57
+ const headers = await broker.inference.getRequestHeaders(providerAddress, JSON.stringify(requestBody));
58
+ const response = await this.fetchImplementation(`${endpoint}/chat/completions`, {
59
+ method: 'POST',
60
+ headers: {
61
+ ...headers,
62
+ 'Content-Type': 'application/json',
63
+ },
64
+ body: JSON.stringify(requestBody),
65
+ });
66
+ if (!response.ok) {
67
+ throw new Error(`0G compute request failed with status ${response.status}`);
68
+ }
69
+ const body = await response.json();
70
+ const chatId = String(response.headers.get('ZG-Res-Key') ?? body.id ?? (0, id_1.createPrefixedId)('chat'));
71
+ const content = this.extractMessageContent(body);
72
+ const teeVerified = Boolean(await broker.inference.processResponse(providerAddress, chatId, JSON.stringify(body.usage ?? { content })));
73
+ const parsed = this.parseEvaluationResponse(content);
74
+ const signerStatus = await broker.inference.checkProviderSignerStatus(providerAddress).catch(() => null);
75
+ const signatureUrl = await broker.inference.getChatSignatureDownloadLink(providerAddress, chatId).catch(() => undefined);
76
+ return {
77
+ decision: parsed.decision,
78
+ confidence: parsed.confidence,
79
+ reason: parsed.reason,
80
+ failedCriteria: parsed.failedCriteria,
81
+ teeVerified,
82
+ teeProof: {
83
+ chatId,
84
+ digest: (0, hash_1.hashText)(content),
85
+ signature: signatureUrl ?? '',
86
+ signerAddress: signerStatus?.teeSignerAddress ?? providerAddress,
87
+ signatureUrl,
88
+ providerAddress,
89
+ },
90
+ };
91
+ }
92
+ renderPrompt(input, artifacts) {
93
+ const inputArtifactsSummary = (0, artifacts_1.buildArtifactSummary)(artifacts.inputImages);
94
+ const resultArtifactsSummary = (0, artifacts_1.buildArtifactSummary)(artifacts.resultImages);
95
+ const artifactValidationIssues = artifacts.issues.length > 0
96
+ ? artifacts.issues.map((issue) => `- ${issue}`).join('\n')
97
+ : 'None';
98
+ if (input.promptTemplate) {
99
+ const rendered = input.promptTemplate
100
+ .replaceAll('{{input}}', JSON.stringify(input.input, null, 2))
101
+ .replaceAll('{{acceptanceCriteria}}', JSON.stringify(input.service.acceptanceCriteria, null, 2))
102
+ .replaceAll('{{result}}', JSON.stringify(input.result, null, 2))
103
+ .replaceAll('{{outputSchema}}', JSON.stringify(input.outputSchema ?? input.service.output.schema, null, 2))
104
+ .replaceAll('{{inputArtifacts}}', inputArtifactsSummary)
105
+ .replaceAll('{{resultArtifacts}}', resultArtifactsSummary)
106
+ .replaceAll('{{artifactValidationIssues}}', artifactValidationIssues);
107
+ if (artifacts.inputImages.length === 0 && artifacts.resultImages.length === 0 && artifacts.issues.length === 0) {
108
+ return rendered;
109
+ }
110
+ return [
111
+ rendered,
112
+ '',
113
+ 'Input image artifacts:',
114
+ inputArtifactsSummary,
115
+ '',
116
+ 'Result image artifacts:',
117
+ resultArtifactsSummary,
118
+ '',
119
+ 'Artifact validation issues:',
120
+ artifactValidationIssues,
121
+ ].join('\n');
122
+ }
123
+ return [
124
+ 'Job input:',
125
+ JSON.stringify(input.input, null, 2),
126
+ '',
127
+ 'Acceptance criteria:',
128
+ JSON.stringify(input.service.acceptanceCriteria, null, 2),
129
+ '',
130
+ 'Expected output schema:',
131
+ JSON.stringify(input.outputSchema ?? input.service.output.schema, null, 2),
132
+ '',
133
+ 'Input image artifacts:',
134
+ inputArtifactsSummary,
135
+ '',
136
+ 'Provider result:',
137
+ JSON.stringify(input.result, null, 2),
138
+ '',
139
+ 'Result image artifacts:',
140
+ resultArtifactsSummary,
141
+ '',
142
+ 'Artifact validation issues:',
143
+ artifactValidationIssues,
144
+ '',
145
+ 'If the returned artifacts are inaccessible, mismatched, or do not satisfy the request, reject the result.',
146
+ '',
147
+ 'Return JSON with fields: decision, confidence, reason, failedCriteria.',
148
+ ].join('\n');
149
+ }
150
+ buildUserContent(prompt, artifacts) {
151
+ if (artifacts.inputImages.length === 0 && artifacts.resultImages.length === 0) {
152
+ return prompt;
153
+ }
154
+ const parts = [
155
+ {
156
+ type: 'text',
157
+ text: prompt,
158
+ },
159
+ ];
160
+ for (const artifact of artifacts.inputImages) {
161
+ parts.push({
162
+ type: 'text',
163
+ text: `Reference input image: ${artifact.path} (${artifact.mimeType}${artifact.width && artifact.height ? `, ${artifact.width}x${artifact.height}` : ''})`,
164
+ });
165
+ parts.push({
166
+ type: 'image_url',
167
+ image_url: {
168
+ url: artifact.dataUrl,
169
+ },
170
+ });
171
+ }
172
+ for (const artifact of artifacts.resultImages) {
173
+ parts.push({
174
+ type: 'text',
175
+ text: `Provider result image: ${artifact.path} (${artifact.mimeType}${artifact.width && artifact.height ? `, ${artifact.width}x${artifact.height}` : ''})`,
176
+ });
177
+ parts.push({
178
+ type: 'image_url',
179
+ image_url: {
180
+ url: artifact.dataUrl,
181
+ },
182
+ });
183
+ }
184
+ return parts;
185
+ }
186
+ extractMessageContent(body) {
187
+ const content = body?.choices?.[0]?.message?.content;
188
+ if (typeof content === 'string') {
189
+ return content;
190
+ }
191
+ if (Array.isArray(content)) {
192
+ return content
193
+ .map((part) => {
194
+ if (typeof part === 'string') {
195
+ return part;
196
+ }
197
+ return typeof part?.text === 'string' ? part.text : JSON.stringify(part);
198
+ })
199
+ .join('\n');
200
+ }
201
+ throw new Error('0G compute response did not include an assistant message');
202
+ }
203
+ parseEvaluationResponse(content) {
204
+ const parsed = JSON.parse(this.extractJson(content));
205
+ const decision = this.parseDecision(parsed.decision);
206
+ const confidenceValue = Number(parsed.confidence);
207
+ const confidence = Number.isFinite(confidenceValue) ? Math.max(0, Math.min(1, confidenceValue)) : 0.5;
208
+ const reason = typeof parsed.reason === 'string' && parsed.reason.length > 0
209
+ ? parsed.reason
210
+ : 'No evaluation reason was returned by the 0G compute provider.';
211
+ const failedCriteria = Array.isArray(parsed.failedCriteria)
212
+ ? parsed.failedCriteria.map((item) => String(item))
213
+ : [];
214
+ return {
215
+ decision,
216
+ confidence,
217
+ reason,
218
+ failedCriteria,
219
+ };
220
+ }
221
+ extractJson(content) {
222
+ const fenced = content.match(/```json\s*([\s\S]+?)\s*```/i);
223
+ if (fenced?.[1]) {
224
+ return fenced[1];
225
+ }
226
+ const firstBrace = content.indexOf('{');
227
+ const lastBrace = content.lastIndexOf('}');
228
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
229
+ return content.slice(firstBrace, lastBrace + 1);
230
+ }
231
+ return content;
232
+ }
233
+ parseDecision(value) {
234
+ if (value === 'approve' || value === 'reject' || value === 'uncertain') {
235
+ return value;
236
+ }
237
+ throw new Error(`Unsupported decision returned by 0G compute provider: ${String(value)}`);
238
+ }
239
+ createWallet() {
240
+ if (!this.privateKey) {
241
+ throw new Error('0G compute mode requires privateKey');
242
+ }
243
+ if (!this.rpcUrl) {
244
+ throw new Error('0G compute mode requires rpcUrl');
245
+ }
246
+ return new ethers_1.Wallet(this.privateKey, new ethers_1.JsonRpcProvider(this.rpcUrl));
247
+ }
248
+ }
249
+ exports.ZeroGComputeService = ZeroGComputeService;
@@ -0,0 +1,28 @@
1
+ export type ObjectStorage = {
2
+ upload<T>(data: T): Promise<string>;
3
+ download<T>(hash: string): Promise<T>;
4
+ exists(hash: string): Promise<boolean>;
5
+ };
6
+ export type ZeroGStorageOptions = {
7
+ storageRoot?: string;
8
+ indexerRpcUrl: string;
9
+ blockchainRpcUrl: string;
10
+ privateKey: string;
11
+ };
12
+ export declare class ZeroGStorageService implements ObjectStorage {
13
+ private readonly objectsRoot;
14
+ private readonly indexerRpcUrl;
15
+ private readonly blockchainRpcUrl;
16
+ private readonly privateKey;
17
+ constructor(options: ZeroGStorageOptions);
18
+ upload<T>(data: T): Promise<string>;
19
+ download<T>(hash: string): Promise<T>;
20
+ exists(hash: string): Promise<boolean>;
21
+ private uploadToZeroG;
22
+ private downloadFromZeroG;
23
+ private existsOnZeroG;
24
+ private getObjectPath;
25
+ private createIndexer;
26
+ private createSigner;
27
+ private getBlockchainRpcUrl;
28
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ZeroGStorageService = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_os_1 = require("node:os");
10
+ const _0g_ts_sdk_1 = require("@0gfoundation/0g-ts-sdk");
11
+ const ethers_1 = require("ethers");
12
+ const json_file_1 = require("../utils/json-file");
13
+ class ZeroGStorageService {
14
+ objectsRoot;
15
+ indexerRpcUrl;
16
+ blockchainRpcUrl;
17
+ privateKey;
18
+ constructor(options) {
19
+ this.objectsRoot = node_path_1.default.resolve(options.storageRoot ?? node_path_1.default.join(process.cwd(), '.halot', 'storage'));
20
+ this.indexerRpcUrl = options.indexerRpcUrl;
21
+ this.blockchainRpcUrl = options.blockchainRpcUrl;
22
+ this.privateKey = options.privateKey;
23
+ (0, json_file_1.ensureDirectory)(this.objectsRoot);
24
+ }
25
+ async upload(data) {
26
+ return this.uploadToZeroG(data);
27
+ }
28
+ async download(hash) {
29
+ return this.downloadFromZeroG(hash);
30
+ }
31
+ async exists(hash) {
32
+ return this.existsOnZeroG(hash);
33
+ }
34
+ async uploadToZeroG(data) {
35
+ const indexer = this.createIndexer();
36
+ const signer = this.createSigner();
37
+ const file = new _0g_ts_sdk_1.MemData(Buffer.from(JSON.stringify(data)));
38
+ const [result, error] = await indexer.upload(file, this.getBlockchainRpcUrl(), signer);
39
+ if (error || !result) {
40
+ throw new Error(`0G upload failed: ${error?.message ?? 'unknown error'}`);
41
+ }
42
+ const rootHash = 'rootHash' in result ? result.rootHash : result.rootHashes[0];
43
+ if (!rootHash) {
44
+ throw new Error('0G upload returned no root hash');
45
+ }
46
+ const cachePath = this.getObjectPath(rootHash);
47
+ if (!node_fs_1.default.existsSync(cachePath)) {
48
+ node_fs_1.default.writeFileSync(cachePath, JSON.stringify(data, null, 2));
49
+ }
50
+ return rootHash;
51
+ }
52
+ async downloadFromZeroG(hash) {
53
+ const cachedPath = this.getObjectPath(hash);
54
+ if (node_fs_1.default.existsSync(cachedPath)) {
55
+ return JSON.parse(node_fs_1.default.readFileSync(cachedPath, 'utf8'));
56
+ }
57
+ const tempPath = node_path_1.default.join((0, node_os_1.tmpdir)(), `halot-0g-${hash}.json`);
58
+ const indexer = this.createIndexer();
59
+ const error = await indexer.download(hash, tempPath, false);
60
+ if (error) {
61
+ throw new Error(`0G download failed for hash ${hash}: ${error.message}`);
62
+ }
63
+ const content = node_fs_1.default.readFileSync(tempPath, 'utf8');
64
+ node_fs_1.default.rmSync(tempPath, { force: true });
65
+ node_fs_1.default.writeFileSync(cachedPath, content);
66
+ return JSON.parse(content);
67
+ }
68
+ async existsOnZeroG(hash) {
69
+ if (node_fs_1.default.existsSync(this.getObjectPath(hash))) {
70
+ return true;
71
+ }
72
+ try {
73
+ const locations = await this.createIndexer().getFileLocations(hash);
74
+ return locations.length > 0;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ getObjectPath(hash) {
81
+ return node_path_1.default.join(this.objectsRoot, `${hash}.json`);
82
+ }
83
+ createIndexer() {
84
+ return new _0g_ts_sdk_1.Indexer(this.indexerRpcUrl);
85
+ }
86
+ createSigner() {
87
+ return new ethers_1.Wallet(this.privateKey, new ethers_1.JsonRpcProvider(this.getBlockchainRpcUrl()));
88
+ }
89
+ getBlockchainRpcUrl() {
90
+ return this.blockchainRpcUrl;
91
+ }
92
+ }
93
+ exports.ZeroGStorageService = ZeroGStorageService;
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@halot/sdk",
3
+ "version": "1.0.0",
4
+ "description": "Shared Halot protocol SDK",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "rm -rf dist && tsc -p tsconfig.json",
9
+ "clean": "rm -rf dist",
10
+ "test": "npm run build && node --test dist/tests/*.test.js",
11
+ "prepack": "npm run build"
12
+ },
13
+ "keywords": [
14
+ "halot",
15
+ "sdk"
16
+ ],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "type": "commonjs",
20
+ "files": [
21
+ "dist/auth",
22
+ "dist/client",
23
+ "dist/middleware",
24
+ "dist/types",
25
+ "dist/utils",
26
+ "dist/x402",
27
+ "dist/zero-g",
28
+ "dist/config.js",
29
+ "dist/config.d.ts",
30
+ "dist/index.js",
31
+ "dist/index.d.ts",
32
+ "README.md"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "default": "./dist/index.js"
41
+ },
42
+ "./middleware": {
43
+ "types": "./dist/middleware/index.d.ts",
44
+ "default": "./dist/middleware/index.js"
45
+ },
46
+ "./client": {
47
+ "types": "./dist/client/index.d.ts",
48
+ "default": "./dist/client/index.js"
49
+ },
50
+ "./*": {
51
+ "types": "./dist/*.d.ts",
52
+ "default": "./dist/*.js"
53
+ }
54
+ },
55
+ "dependencies": {
56
+ "@0gfoundation/0g-ts-sdk": "^1.2.1",
57
+ "@0glabs/0g-serving-broker": "^0.7.4",
58
+ "ethers": "6.13.1",
59
+ "zod": "^4.3.6"
60
+ },
61
+ "devDependencies": {
62
+ "@types/express": "^5.0.6",
63
+ "@types/node": "^25.5.2",
64
+ "typescript": "^6.0.2"
65
+ }
66
+ }